diff --git a/.gitattributes b/.gitattributes index 05b1a132398..1e9bf994ead 100644 --- a/.gitattributes +++ b/.gitattributes @@ -2,3 +2,5 @@ **/ModuleBindings/** linguist-generated=true eol=lf /docs/llms/** linguist-generated=true /docs/llms/*-details.json linguist-generated=false +/tools/stack-bench/** text eol=lf +/tools/stack-bench/**/*.woff2 -text -diff diff --git a/.gitignore b/.gitignore index 1f3b49ecd2d..2c2f6b629ef 100644 --- a/.gitignore +++ b/.gitignore @@ -267,3 +267,6 @@ nul # Any local file *.local + +# Local working notes and temporary builds +/local-notes/ diff --git a/codex-plugin/plugins/spacetimedb/skills/cli/SKILL.md b/codex-plugin/plugins/spacetimedb/skills/cli/SKILL.md index 534ad7ee4ec..ef79e125529 100644 --- a/codex-plugin/plugins/spacetimedb/skills/cli/SKILL.md +++ b/codex-plugin/plugins/spacetimedb/skills/cli/SKILL.md @@ -43,13 +43,15 @@ spacetime build --debug # faster iteration, slower runtime # Dev mode (auto-rebuild, auto-publish, generates bindings) spacetime dev -spacetime dev --client-lang typescript --module-bindings-path ./client/src/module_bindings +spacetime dev my-database --server local --yes --delete-data=never --client-lang typescript --module-bindings-path ./client/src/module_bindings # Generate client bindings spacetime generate --lang typescript|csharp|rust --out-dir ./bindings --module-path ./server spacetime generate --lang unrealcpp --uproject-dir ./MyGame --module-path ./server --unreal-module-name MyGame ``` +`dev` stays running and watches module changes. `--run "npm run dev"` starts a client command; `--server-only` omits it. `--module-path` selects the module directory when no publish targets exist in `spacetime.json`. Once targets exist, use their configured paths and omit that flag. Separate build/publish/generate commands remain useful for one-shot deployment. + ### Publishing & Deployment ```bash @@ -112,7 +114,7 @@ spacetime server add myserver --url https://my-spacetime.example.com # Set default server spacetime server set-default local -# Test connectivity +# Check connectivity spacetime server ping local # Start local instance @@ -169,10 +171,7 @@ spacetime server ping ``` ### "Schema conflict" -```bash -# Clear data and republish -spacetime publish my-db --delete-data=always --yes -``` +`--delete-data=never` rejects incompatible schema updates without clearing data. A compatible migration preserves existing data; `--delete-data=always` destroys it and is only appropriate for an intentional reset. ### "Build failed" ```bash diff --git a/codex-plugin/plugins/spacetimedb/skills/concepts/SKILL.md b/codex-plugin/plugins/spacetimedb/skills/concepts/SKILL.md index 8ea6e8f9cfb..e152e5d9e72 100644 --- a/codex-plugin/plugins/spacetimedb/skills/concepts/SKILL.md +++ b/codex-plugin/plugins/spacetimedb/skills/concepts/SKILL.md @@ -101,8 +101,8 @@ Lifecycle: Write → Compile → Publish (`spacetime publish`) → Hot-swap (rep ## Identity -- **Identity**: A long-lived, globally unique identifier for a user. -- **ConnectionId**: Identifies a specific client connection. +- **Identity**: A long-lived, globally unique identifier for a user, derived from the token's issuer and subject claims. The same token yields the same identity on every connection. +- **ConnectionId**: Identifies one client connection. A new connection gets a new connection ID; a disconnect ends the connection, not the identity. - Always use `ctx.sender` / `ctx.Sender` / `ctx.sender()` for authorization. SpacetimeDB works with many OIDC providers, including SpacetimeAuth (built-in), Auth0, Clerk, Keycloak, Google, and GitHub. diff --git a/codex-plugin/plugins/spacetimedb/skills/cpp-server/SKILL.md b/codex-plugin/plugins/spacetimedb/skills/cpp-server/SKILL.md index 8d270e93080..860531d9d71 100644 --- a/codex-plugin/plugins/spacetimedb/skills/cpp-server/SKILL.md +++ b/codex-plugin/plugins/spacetimedb/skills/cpp-server/SKILL.md @@ -138,6 +138,8 @@ SPACETIMEDB_CLIENT_DISCONNECTED(on_disconnect, ReducerContext ctx) { } ``` +Connection hooks run once per connection. The same authenticated principal keeps the same identity (`ctx.sender()`) across connections, while each connection has its own connection ID (`ctx.connection_id()`). A disconnect ends one connection; it does not end the identity, which returns unchanged on the next connection with the same token. Use connection IDs for presence and other connection-scoped state. + ## Authentication & Timestamps ```cpp diff --git a/codex-plugin/plugins/spacetimedb/skills/csharp-server/SKILL.md b/codex-plugin/plugins/spacetimedb/skills/csharp-server/SKILL.md index 1d08ba89fe7..b1037f599c3 100644 --- a/codex-plugin/plugins/spacetimedb/skills/csharp-server/SKILL.md +++ b/codex-plugin/plugins/spacetimedb/skills/csharp-server/SKILL.md @@ -162,7 +162,9 @@ public static void OnConnect(ReducerContext ctx) { ... } public static void OnDisconnect(ReducerContext ctx) { ... } ``` -`ctx.ConnectionId` is `ConnectionId?`, including in connection lifecycle reducers. Check or unwrap it before storing it in a non-nullable column or passing it to an index accessor. +Connection hooks run once per connection. The same authenticated principal keeps the same identity (`ctx.Sender`) across connections, while each connection has its own connection ID (`ctx.ConnectionId`). A disconnect ends one connection; it does not end the identity, which returns unchanged on the next connection with the same token. Use connection IDs for presence and other connection-scoped state. + +`ctx.ConnectionId` is typed `ConnectionId?`. It is present inside connection lifecycle reducers and reducers invoked over a connection, and null in `Init` and scheduled reducers. Check or unwrap it before storing it in a non-nullable column or passing it to an index accessor. ## Views diff --git a/codex-plugin/plugins/spacetimedb/skills/rust-server/SKILL.md b/codex-plugin/plugins/spacetimedb/skills/rust-server/SKILL.md index 0e282242263..ec8e772c9c9 100644 --- a/codex-plugin/plugins/spacetimedb/skills/rust-server/SKILL.md +++ b/codex-plugin/plugins/spacetimedb/skills/rust-server/SKILL.md @@ -150,6 +150,8 @@ pub fn on_connect(ctx: &ReducerContext) { ... } pub fn on_disconnect(ctx: &ReducerContext) { ... } ``` +Connection hooks run once per connection. The same authenticated principal keeps the same identity (`ctx.sender()`) across connections, while each connection has its own connection ID (`ctx.connection_id()`). A disconnect ends one connection; it does not end the identity, which returns unchanged on the next connection with the same token. Use connection IDs for presence and other connection-scoped state. + The current connection ID is available through `ctx.connection_id()` (not a public field) and may be absent outside connection-scoped calls. ## Views diff --git a/codex-plugin/plugins/spacetimedb/skills/typescript-client/SKILL.md b/codex-plugin/plugins/spacetimedb/skills/typescript-client/SKILL.md index 3a31183133f..dff16e1dd3c 100644 --- a/codex-plugin/plugins/spacetimedb/skills/typescript-client/SKILL.md +++ b/codex-plugin/plugins/spacetimedb/skills/typescript-client/SKILL.md @@ -18,7 +18,7 @@ Generated bindings convert snake_case names to camelCase, including row fields: ## React: main.tsx ```typescript -import React, { useEffect, useMemo } from 'react'; +import React, { useMemo } from 'react'; import ReactDOM from 'react-dom/client'; import { SpacetimeDBProvider } from 'spacetimedb/react'; import { DbConnection } from './module_bindings'; @@ -30,6 +30,7 @@ function Root() { DbConnection.builder() .withUri(SPACETIMEDB_URI) .withDatabaseName(MODULE_NAME) + // Reuse the token issued on the previous connection. .withToken(localStorage.getItem('auth_token') || undefined), [] ); @@ -46,27 +47,18 @@ ReactDOM.createRoot(document.getElementById('root')!).render(); ## React: App.tsx ```typescript +import { useEffect } from 'react'; import { useTable, useSpacetimeDB } from 'spacetimedb/react'; import { DbConnection, tables } from './module_bindings'; function App() { - const { isActive, identity: myIdentity, token, getConnection } = useSpacetimeDB(); + const { identity: myIdentity, token, getConnection } = useSpacetimeDB(); const conn = getConnection() as DbConnection | null; - // Save auth token + // Persist the issued token for the next page load. useEffect(() => { if (token) localStorage.setItem('auth_token', token); }, [token]); - // Subscribe when connected. Prefer typed query builders over raw SQL - useEffect(() => { - if (!conn || !isActive) return; - conn.subscriptionBuilder() - .onApplied(() => setSubscribed(true)) - .subscribe([tables.entity, tables.record]); - // Or with filters: tables.entity.where(r => r.active.eq(true)) - // Or raw SQL: 'SELECT * FROM entity' - }, [conn, isActive]); - - // Reactive data. Returns [rows, isReady] + // useTable owns the subscription and cleanup. Returns [rows, isReady]. const [entities, entitiesReady] = useTable(tables.entity); const [records, recordsReady] = useTable(tables.record); @@ -80,8 +72,8 @@ function App() { } ); - // Call reducers with object syntax - conn?.reducers.addRecord({ data }).catch(console.error); + // A callback for a UI event; defining it does not call the reducer during render. + const addRecord = (data: string) => conn?.reducers.addRecord({ data }).catch(console.error); // Compare identities const isMe = row.owner.toHexString() === myIdentity?.toHexString(); @@ -111,7 +103,9 @@ conn.db.user.onUpdate((ctx, oldUser, newUser) => console.log('Updated:', newUser ## Gotchas -- **`useTable` rows are `readonly`.** Copy before sorting/mutating, or it fails to type-check: +- **Subscription rows have no presentation order.** A server view's array order does not + define client cache iteration order. `useTable` rows are `readonly`; a sorted copy can + express the application's display order: `const [rows] = useTable(tables.message); const sorted = [...rows].sort(...)`. -- **bigint in JSX.** ids/counts from `t.u64()`/`t.i64()` columns are `bigint`, which React - cannot render. Wrap it: `{Number(row.id)}` or `{String(count)}`. +- **64-bit display values.** `{String(row.id)}` preserves the full `bigint` value. + Conversion to `Number` can lose precision outside JavaScript's safe integer range. diff --git a/codex-plugin/plugins/spacetimedb/skills/typescript-server/SKILL.md b/codex-plugin/plugins/spacetimedb/skills/typescript-server/SKILL.md index c9f2e7343fd..07cbca54a22 100644 --- a/codex-plugin/plugins/spacetimedb/skills/typescript-server/SKILL.md +++ b/codex-plugin/plugins/spacetimedb/skills/typescript-server/SKILL.md @@ -98,6 +98,11 @@ Every column is a `t` builder value: Modifiers: `.primaryKey()`, `.autoInc()`, `.unique()`, `.index('btree')`, `.default(value)`. +`.primaryKey()` and `.unique()` apply to one column. For uniqueness across +multiple columns, use a surrogate key, the multi-column index below, and a +reducer that rejects an existing index match before inserting. An index alone +does not enforce uniqueness. + Use `.default(value)` only for a newly appended migration-safe field. Do not put defaults on primary-key, unique, or auto-increment columns. Optional columns: `nickname: t.option(t.string())` @@ -130,7 +135,9 @@ export { default } from './schema'; // re-export the schema for the module ent ## Reducers -Reducers are created with `spacetimedb.reducer(...)`; the export name becomes the reducer name: +Reducers are created with `spacetimedb.reducer(...)`. An exported `signUp` +becomes `signUp` in generated clients and `sign_up` in `spacetime call` and +`describe`: ```typescript export const createEntity = spacetimedb.reducer( @@ -178,10 +185,17 @@ export const onConnect = spacetimedb.clientConnected((ctx) => { ... }); export const onDisconnect = spacetimedb.clientDisconnected((ctx) => { ... }); ``` -`ctx.connectionId` is `ConnectionId | null`, including in lifecycle contexts. Guard it before passing it to a helper or using it as a table key. +Connection hooks run once per connection. The same authenticated principal keeps the same identity (`ctx.sender`) across connections, while each connection has its own connection ID (`ctx.connectionId`). A disconnect ends one connection; it does not end the identity, which returns unchanged on the next connection with the same token. Use connection IDs for presence and other connection-scoped state. Reloads and temporary network loss also disconnect clients; application login expiry and explicit sign-out are separate from connection cleanup. + +`ctx.connectionId` is typed `ConnectionId | null`. It is present inside connection lifecycle hooks and reducers invoked over a connection, and `null` in `init` and scheduled reducers. Guard it before passing it to a helper or using it as a table key. ## Reducer Context API +Each reducer call runs in one database transaction. An error that escapes the +reducer rolls back its database changes. `ctx.sender` identifies the caller; +application roles and permissions are not inferred from that identity. Table +visibility and view filters control reads, not authorization to call reducers. + `ctx` is the only source of sender identity, time, and randomness; stdlib clocks and RNG are unavailable in modules. Let exported callbacks infer their context type. In helpers, use `ReducerCtx>`; do not annotate a context as `any`, because that erases table row types and can make `bigint` expressions infer as `number`. ```typescript @@ -278,9 +292,22 @@ const Shape = t.enum('Shape', { A client subscribing to a view receives only the rows it returns. Use a per-user view (keyed on `ctx.sender`) for per-viewer access control: deleting a row it depends on (e.g. a membership row) automatically drops the rows it was exposing from that client. +Use index accessors in views. Do not scan a whole table with `.iter()` when an +indexed lookup can select the required rows. `t.row(...)` and `t.object(...)` return schema builders, not TypeScript runtime row types. Let a view callback infer its result, or annotate a separately declared structural type such as `Array<{ sku: bigint; label: string }>`. A named output type must not reuse the generated PascalCase name of its view accessor (for example, reserve `DiscountedProduct` for a `discounted_product` view). +A view context is `ViewCtx` (and `AnonymousViewCtx`), both exported from +`spacetimedb/server`. It carries `sender`, a read-only `db`, and `from`; it is +not a `ReducerCtx`, so a helper shared between a reducer and a view must accept +either: + +```typescript +import type { ReducerCtx, ViewCtx, InferSchema } from 'spacetimedb/server'; +type S = InferSchema; +function stockOf(ctx: ReducerCtx | ViewCtx, itemId: bigint) { ... } +``` + Both `spacetimedb.view(...)` and `spacetimedb.anonymousView(...)` take three arguments: view options, the declared return schema, and the callback. ```typescript @@ -288,7 +315,7 @@ Both `spacetimedb.view(...)` and `spacetimedb.anonymousView(...)` take three arg export const activeUsers = spacetimedb.anonymousView( { name: 'active_users', public: true }, t.array(entity.rowType), - (ctx) => [...ctx.db.entity.iter()].filter(e => e.active) + (ctx) => [...ctx.db.entity.active.filter(true)] // active: t.bool().index('btree') ); // Per-user view (varies by ctx.sender): diff --git a/crates/bindings-typescript/src/lib/query.ts b/crates/bindings-typescript/src/lib/query.ts index bb93b0e6ce3..0c17e3d145a 100644 --- a/crates/bindings-typescript/src/lib/query.ts +++ b/crates/bindings-typescript/src/lib/query.ts @@ -248,19 +248,21 @@ export type NamespacedQueryBuilder = * A runtime reference to a table. This materializes the RowExpr for us. * TODO: Maybe add the full SchemaDef to the type signature depending on how joins will work. */ -export type TableRef = Readonly<{ - type: 'table'; - sourceName: TableDef['sourceName']; - accessorName: string; - cols: RowExpr; - indexedCols: IndexedRowExpr; - tableDef: TableDef; +// Keep this named so TypeScript diagnostics show `TableRef` instead of its +// expanded structure. +export interface TableRef { + readonly type: 'table'; + readonly sourceName: TableDef['sourceName']; + readonly accessorName: string; + readonly cols: RowExpr; + readonly indexedCols: IndexedRowExpr; + readonly tableDef: TableDef; // Delegated UntypedTableDef properties for compatibility. - columns: TableDef['columns']; - indexes: TableDef['indexes']; - rowType: TableDef['rowType']; - constraints: any; -}>; + readonly columns: TableDef['columns']; + readonly indexes: TableDef['indexes']; + readonly rowType: TableDef['rowType']; + readonly constraints: any; +} class TableRefImpl implements TableRef, From diff --git a/crates/bindings-typescript/tests/table_ref_error_message.test.ts b/crates/bindings-typescript/tests/table_ref_error_message.test.ts new file mode 100644 index 00000000000..009a9c192dd --- /dev/null +++ b/crates/bindings-typescript/tests/table_ref_error_message.test.ts @@ -0,0 +1,79 @@ +import { mkdtempSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import * as ts from 'typescript'; +import { describe, expect, it } from 'vitest'; + +const bindingsRoot = path.resolve( + path.dirname(fileURLToPath(import.meta.url)), + '..' +); + +function runTypecheck(source: string) { + const tmpDir = mkdtempSync(path.join(tmpdir(), 'stdb-tableref-diag-')); + const reproPath = path.join(tmpDir, 'repro.ts'); + writeFileSync(reproPath, source); + + try { + const options: ts.CompilerOptions = { + target: ts.ScriptTarget.ESNext, + module: ts.ModuleKind.ESNext, + strict: true, + noEmit: true, + skipLibCheck: true, + forceConsistentCasingInFileNames: true, + allowImportingTsExtensions: true, + noImplicitAny: true, + moduleResolution: ts.ModuleResolutionKind.Bundler, + useDefineForClassFields: true, + verbatimModuleSyntax: true, + isolatedModules: true, + }; + + const host = ts.createCompilerHost(options); + const program = ts.createProgram( + [reproPath, path.join(bindingsRoot, 'src/server/sys.d.ts')], + options, + host + ); + const diagnostics = ts.getPreEmitDiagnostics(program); + return diagnostics.map(d => + ts.flattenDiagnosticMessageText(d.messageText, '\n') + ); + } finally { + rmSync(tmpDir, { recursive: true, force: true }); + } +} + +describe('TableRef diagnostics', () => { + const source = ` +import { t } from ${JSON.stringify(path.join(bindingsRoot, 'src/server/index.ts'))}; +import { table } from ${JSON.stringify(path.join(bindingsRoot, 'src/lib/table.ts'))}; +import { createTableRefFromDef } from ${JSON.stringify(path.join(bindingsRoot, 'src/lib/query.ts'))}; +import type { AllUnique } from ${JSON.stringify(path.join(bindingsRoot, 'src/lib/constraints.ts'))}; + +const cartItem = table( + { name: 'cart_item' }, + { id: t.u64().primaryKey().autoInc(), accountId: t.u64(), quantity: t.u32() } +); + +const ref = createTableRefFromDef(cartItem as any, 'cartItem'); +type Boom = AllUnique; +declare const b: Boom; +`; + + it('names the type instead of dumping its structure', () => { + const messages = runTypecheck(source); + const constraintError = messages.find(m => + m.includes("does not satisfy the constraint 'UntypedTableDef'") + ); + + expect(constraintError).toBeDefined(); + // The name, not the shape. + expect(constraintError).toContain('TableRef<'); + expect(constraintError).not.toContain('type: "table"'); + expect(constraintError).not.toContain('accessorName'); + expect(constraintError.length).toBeLessThan(250); + }, 15000); +}); diff --git a/crates/cli/build.rs b/crates/cli/build.rs index c5bd4303464..7e7d755cae5 100644 --- a/crates/cli/build.rs +++ b/crates/cli/build.rs @@ -6,6 +6,7 @@ use std::process::Command; use toml::Value; fn main() { + println!("cargo:rerun-if-env-changed=SPACETIMEDB_NIX_BUILD_GIT_COMMIT"); let git_hash = find_git_hash(); println!("cargo:rustc-env=GIT_HASH={git_hash}"); @@ -110,6 +111,7 @@ fn generate_template_files() { // Embed skill files from skills/*/SKILL.md let skills_dir = repo_root.join("skills"); + println!("cargo:rerun-if-changed={}", skills_dir.display()); let skill_names = discover_skill_names(&skills_dir); generated_code.push_str("pub fn get_skill(name: &str) -> Option<&'static str> {\n"); diff --git a/crates/cli/src/subcommands/dev.rs b/crates/cli/src/subcommands/dev.rs index 95cc579182f..ef2465cff0a 100644 --- a/crates/cli/src/subcommands/dev.rs +++ b/crates/cli/src/subcommands/dev.rs @@ -85,6 +85,12 @@ pub fn cli() -> Command { ) .arg(common_args::server().help("The nickname, host name or URL of the server to publish to")) .arg(common_args::yes()) + .arg( + Arg::new("ready-file") + .long("ready-file") + .value_parser(clap::value_parser!(PathBuf)) + .help("Write this file after the initial build cycle succeeds and file watching starts. This is a startup receipt, not ongoing health."), + ) .arg(common_args::clear_database()) .arg( Arg::new("template") @@ -150,6 +156,13 @@ struct DatabaseRow { } pub async fn exec(mut config: Config, args: &ArgMatches) -> Result<(), anyhow::Error> { + if let Some(path) = args.get_one::("ready-file") { + match fs::remove_file(path) { + Ok(()) => {} + Err(error) if error.kind() == std::io::ErrorKind::NotFound => {} + Err(error) => return Err(error).context("Failed to clear development readiness file"), + } + } let project_path = args.get_one::("project-path").unwrap(); let module_path_from_cli = args.get_one::("module-path"); let module_bindings_path = args.get_one::("module-bindings-path").unwrap(); @@ -760,7 +773,7 @@ pub async fn exec(mut config: Config, args: &ArgMatches) -> Result<(), anyhow::E let loaded_config_dir = loaded_config.as_ref().map(|lc| lc.config_dir.clone()); generate_build_and_publish( - &config, + &mut config, &project_dir, loaded_config_dir.as_deref(), &spacetimedb_dir, @@ -861,6 +874,10 @@ pub async fn exec(mut config: Config, args: &ArgMatches) -> Result<(), anyhow::E watcher.watch(watch_dir, RecursiveMode::Recursive)?; } + if let Some(path) = args.get_one::("ready-file") { + fs::write(path, "ready\n").context("Failed to write development readiness file")?; + } + let mut debounce_timer; loop { // Use recv_timeout so we can periodically check if the client process exited @@ -876,7 +893,7 @@ pub async fn exec(mut config: Config, args: &ArgMatches) -> Result<(), anyhow::E println!("\n{}", "File change detected, rebuilding...".yellow()); match generate_build_and_publish( - &config, + &mut config, &project_dir, loaded_config_dir.as_deref(), &spacetimedb_dir, @@ -1024,7 +1041,7 @@ fn upsert_env_db_names_and_hosts(env_path: &Path, server_host_url: &str, databas #[allow(clippy::too_many_arguments)] async fn generate_build_and_publish( - config: &Config, + config: &mut Config, project_dir: &Path, config_dir: Option<&Path>, spacetimedb_dir: &Path, @@ -1181,7 +1198,8 @@ async fn generate_build_and_publish( publish_entry.insert("break-clients".to_string(), json!(true)); } - publish::exec_from_entry(config.clone(), publish_entry, config_dir, clear_database, yes).await?; + // Preserve a token created during publish for logs and later rebuilds. + publish::exec_from_entry(config, publish_entry, config_dir, clear_database, yes).await?; } println!("{}", "Published successfully!".green().bold()); @@ -2043,12 +2061,17 @@ mod tests { // Verify that --skip-publish and --skip-generate flags are registered let cmd = cli(); - let matches = cmd - .clone() - .get_matches_from(vec!["dev", "--skip-publish", "--skip-generate"]); + let matches = cmd.clone().get_matches_from(vec![ + "dev", + "--skip-publish", + "--skip-generate", + "--ready-file", + "ready", + ]); assert!(matches.get_flag("skip_publish")); assert!(matches.get_flag("skip_generate")); + assert_eq!(matches.get_one::("ready-file"), Some(&PathBuf::from("ready"))); } #[test] diff --git a/crates/cli/src/subcommands/publish.rs b/crates/cli/src/subcommands/publish.rs index 745664880f0..63d704d25af 100644 --- a/crates/cli/src/subcommands/publish.rs +++ b/crates/cli/src/subcommands/publish.rs @@ -450,7 +450,7 @@ pub async fn exec_with_options( } pub async fn exec_from_entry( - mut config: Config, + config: &mut Config, entry: HashMap, config_dir: Option<&std::path::Path>, clear_database: ClearMode, @@ -465,7 +465,7 @@ pub async fn exec_from_entry( let yes = if force { YesFlags::all() } else { YesFlags::default() }; - execute_publish_configs(&mut config, vec![command_config], true, config_dir, clear_database, yes).await + execute_publish_configs(config, vec![command_config], true, config_dir, clear_database, yes).await } async fn execute_publish_configs<'a>( diff --git a/crates/codegen/build.rs b/crates/codegen/build.rs index cd3bca12faf..da856e01b55 100644 --- a/crates/codegen/build.rs +++ b/crates/codegen/build.rs @@ -3,6 +3,7 @@ use std::process::Command; // https://stackoverflow.com/questions/43753491/include-git-commit-hash-as-string-into-rust-program #[allow(clippy::disallowed_macros)] fn main() { + println!("cargo:rerun-if-env-changed=SPACETIMEDB_NIX_BUILD_GIT_COMMIT"); let git_hash = find_git_hash(); println!("cargo:rustc-env=GIT_HASH={git_hash}"); } diff --git a/crates/fs-utils/src/lib.rs b/crates/fs-utils/src/lib.rs index c4d1a6ba0c1..42e5a51ae25 100644 --- a/crates/fs-utils/src/lib.rs +++ b/crates/fs-utils/src/lib.rs @@ -35,12 +35,36 @@ pub fn atomic_write(file_path: &Path, data: String) -> anyhow::Result<()> { .write(true) .create_new(true) .open(&temp_path); - if let Ok(file) = opened { - temp_file = file; - break; + match opened { + Ok(file) => { + temp_file = file; + break; + } + Err(error) if error.kind() == std::io::ErrorKind::AlreadyExists => continue, + Err(error) => return Err(error.into()), } } temp_file.write_all(data.as_bytes())?; std::fs::rename(&temp_path, file_path)?; Ok(()) } + +#[cfg(test)] +mod tests { + use super::atomic_write; + + #[test] + fn atomic_write_replaces_contents_and_returns_open_errors() { + let dir = tempdir::TempDir::new("atomic-write").unwrap(); + let path = dir.path().join("config"); + atomic_write(&path, "before".into()).unwrap(); + atomic_write(&path, "after".into()).unwrap(); + assert_eq!(std::fs::read_to_string(&path).unwrap(), "after"); + + let error = atomic_write(&dir.path().join("missing/config"), "data".into()).unwrap_err(); + assert_eq!( + error.downcast_ref::().unwrap().kind(), + std::io::ErrorKind::NotFound + ); + } +} diff --git a/skills/cli/SKILL.md b/skills/cli/SKILL.md index 534ad7ee4ec..ef79e125529 100644 --- a/skills/cli/SKILL.md +++ b/skills/cli/SKILL.md @@ -43,13 +43,15 @@ spacetime build --debug # faster iteration, slower runtime # Dev mode (auto-rebuild, auto-publish, generates bindings) spacetime dev -spacetime dev --client-lang typescript --module-bindings-path ./client/src/module_bindings +spacetime dev my-database --server local --yes --delete-data=never --client-lang typescript --module-bindings-path ./client/src/module_bindings # Generate client bindings spacetime generate --lang typescript|csharp|rust --out-dir ./bindings --module-path ./server spacetime generate --lang unrealcpp --uproject-dir ./MyGame --module-path ./server --unreal-module-name MyGame ``` +`dev` stays running and watches module changes. `--run "npm run dev"` starts a client command; `--server-only` omits it. `--module-path` selects the module directory when no publish targets exist in `spacetime.json`. Once targets exist, use their configured paths and omit that flag. Separate build/publish/generate commands remain useful for one-shot deployment. + ### Publishing & Deployment ```bash @@ -112,7 +114,7 @@ spacetime server add myserver --url https://my-spacetime.example.com # Set default server spacetime server set-default local -# Test connectivity +# Check connectivity spacetime server ping local # Start local instance @@ -169,10 +171,7 @@ spacetime server ping ``` ### "Schema conflict" -```bash -# Clear data and republish -spacetime publish my-db --delete-data=always --yes -``` +`--delete-data=never` rejects incompatible schema updates without clearing data. A compatible migration preserves existing data; `--delete-data=always` destroys it and is only appropriate for an intentional reset. ### "Build failed" ```bash diff --git a/skills/concepts/SKILL.md b/skills/concepts/SKILL.md index 8ea6e8f9cfb..e152e5d9e72 100644 --- a/skills/concepts/SKILL.md +++ b/skills/concepts/SKILL.md @@ -101,8 +101,8 @@ Lifecycle: Write → Compile → Publish (`spacetime publish`) → Hot-swap (rep ## Identity -- **Identity**: A long-lived, globally unique identifier for a user. -- **ConnectionId**: Identifies a specific client connection. +- **Identity**: A long-lived, globally unique identifier for a user, derived from the token's issuer and subject claims. The same token yields the same identity on every connection. +- **ConnectionId**: Identifies one client connection. A new connection gets a new connection ID; a disconnect ends the connection, not the identity. - Always use `ctx.sender` / `ctx.Sender` / `ctx.sender()` for authorization. SpacetimeDB works with many OIDC providers, including SpacetimeAuth (built-in), Auth0, Clerk, Keycloak, Google, and GitHub. diff --git a/skills/cpp-server/SKILL.md b/skills/cpp-server/SKILL.md index 8d270e93080..860531d9d71 100644 --- a/skills/cpp-server/SKILL.md +++ b/skills/cpp-server/SKILL.md @@ -138,6 +138,8 @@ SPACETIMEDB_CLIENT_DISCONNECTED(on_disconnect, ReducerContext ctx) { } ``` +Connection hooks run once per connection. The same authenticated principal keeps the same identity (`ctx.sender()`) across connections, while each connection has its own connection ID (`ctx.connection_id()`). A disconnect ends one connection; it does not end the identity, which returns unchanged on the next connection with the same token. Use connection IDs for presence and other connection-scoped state. + ## Authentication & Timestamps ```cpp diff --git a/skills/csharp-server/SKILL.md b/skills/csharp-server/SKILL.md index 1d08ba89fe7..b1037f599c3 100644 --- a/skills/csharp-server/SKILL.md +++ b/skills/csharp-server/SKILL.md @@ -162,7 +162,9 @@ public static void OnConnect(ReducerContext ctx) { ... } public static void OnDisconnect(ReducerContext ctx) { ... } ``` -`ctx.ConnectionId` is `ConnectionId?`, including in connection lifecycle reducers. Check or unwrap it before storing it in a non-nullable column or passing it to an index accessor. +Connection hooks run once per connection. The same authenticated principal keeps the same identity (`ctx.Sender`) across connections, while each connection has its own connection ID (`ctx.ConnectionId`). A disconnect ends one connection; it does not end the identity, which returns unchanged on the next connection with the same token. Use connection IDs for presence and other connection-scoped state. + +`ctx.ConnectionId` is typed `ConnectionId?`. It is present inside connection lifecycle reducers and reducers invoked over a connection, and null in `Init` and scheduled reducers. Check or unwrap it before storing it in a non-nullable column or passing it to an index accessor. ## Views diff --git a/skills/rust-server/SKILL.md b/skills/rust-server/SKILL.md index 0e282242263..ec8e772c9c9 100644 --- a/skills/rust-server/SKILL.md +++ b/skills/rust-server/SKILL.md @@ -150,6 +150,8 @@ pub fn on_connect(ctx: &ReducerContext) { ... } pub fn on_disconnect(ctx: &ReducerContext) { ... } ``` +Connection hooks run once per connection. The same authenticated principal keeps the same identity (`ctx.sender()`) across connections, while each connection has its own connection ID (`ctx.connection_id()`). A disconnect ends one connection; it does not end the identity, which returns unchanged on the next connection with the same token. Use connection IDs for presence and other connection-scoped state. + The current connection ID is available through `ctx.connection_id()` (not a public field) and may be absent outside connection-scoped calls. ## Views diff --git a/skills/typescript-client/SKILL.md b/skills/typescript-client/SKILL.md index 3a31183133f..dff16e1dd3c 100644 --- a/skills/typescript-client/SKILL.md +++ b/skills/typescript-client/SKILL.md @@ -18,7 +18,7 @@ Generated bindings convert snake_case names to camelCase, including row fields: ## React: main.tsx ```typescript -import React, { useEffect, useMemo } from 'react'; +import React, { useMemo } from 'react'; import ReactDOM from 'react-dom/client'; import { SpacetimeDBProvider } from 'spacetimedb/react'; import { DbConnection } from './module_bindings'; @@ -30,6 +30,7 @@ function Root() { DbConnection.builder() .withUri(SPACETIMEDB_URI) .withDatabaseName(MODULE_NAME) + // Reuse the token issued on the previous connection. .withToken(localStorage.getItem('auth_token') || undefined), [] ); @@ -46,27 +47,18 @@ ReactDOM.createRoot(document.getElementById('root')!).render(); ## React: App.tsx ```typescript +import { useEffect } from 'react'; import { useTable, useSpacetimeDB } from 'spacetimedb/react'; import { DbConnection, tables } from './module_bindings'; function App() { - const { isActive, identity: myIdentity, token, getConnection } = useSpacetimeDB(); + const { identity: myIdentity, token, getConnection } = useSpacetimeDB(); const conn = getConnection() as DbConnection | null; - // Save auth token + // Persist the issued token for the next page load. useEffect(() => { if (token) localStorage.setItem('auth_token', token); }, [token]); - // Subscribe when connected. Prefer typed query builders over raw SQL - useEffect(() => { - if (!conn || !isActive) return; - conn.subscriptionBuilder() - .onApplied(() => setSubscribed(true)) - .subscribe([tables.entity, tables.record]); - // Or with filters: tables.entity.where(r => r.active.eq(true)) - // Or raw SQL: 'SELECT * FROM entity' - }, [conn, isActive]); - - // Reactive data. Returns [rows, isReady] + // useTable owns the subscription and cleanup. Returns [rows, isReady]. const [entities, entitiesReady] = useTable(tables.entity); const [records, recordsReady] = useTable(tables.record); @@ -80,8 +72,8 @@ function App() { } ); - // Call reducers with object syntax - conn?.reducers.addRecord({ data }).catch(console.error); + // A callback for a UI event; defining it does not call the reducer during render. + const addRecord = (data: string) => conn?.reducers.addRecord({ data }).catch(console.error); // Compare identities const isMe = row.owner.toHexString() === myIdentity?.toHexString(); @@ -111,7 +103,9 @@ conn.db.user.onUpdate((ctx, oldUser, newUser) => console.log('Updated:', newUser ## Gotchas -- **`useTable` rows are `readonly`.** Copy before sorting/mutating, or it fails to type-check: +- **Subscription rows have no presentation order.** A server view's array order does not + define client cache iteration order. `useTable` rows are `readonly`; a sorted copy can + express the application's display order: `const [rows] = useTable(tables.message); const sorted = [...rows].sort(...)`. -- **bigint in JSX.** ids/counts from `t.u64()`/`t.i64()` columns are `bigint`, which React - cannot render. Wrap it: `{Number(row.id)}` or `{String(count)}`. +- **64-bit display values.** `{String(row.id)}` preserves the full `bigint` value. + Conversion to `Number` can lose precision outside JavaScript's safe integer range. diff --git a/skills/typescript-server/SKILL.md b/skills/typescript-server/SKILL.md index c9f2e7343fd..7876171a358 100644 --- a/skills/typescript-server/SKILL.md +++ b/skills/typescript-server/SKILL.md @@ -98,6 +98,11 @@ Every column is a `t` builder value: Modifiers: `.primaryKey()`, `.autoInc()`, `.unique()`, `.index('btree')`, `.default(value)`. +`.primaryKey()` and `.unique()` apply to one column. For uniqueness across +multiple columns, use a surrogate key, the multi-column index below, and a +reducer that rejects an existing index match before inserting. An index alone +does not enforce uniqueness. + Use `.default(value)` only for a newly appended migration-safe field. Do not put defaults on primary-key, unique, or auto-increment columns. Optional columns: `nickname: t.option(t.string())` @@ -130,7 +135,9 @@ export { default } from './schema'; // re-export the schema for the module ent ## Reducers -Reducers are created with `spacetimedb.reducer(...)`; the export name becomes the reducer name: +Reducers are created with `spacetimedb.reducer(...)`. An exported `signUp` +becomes `signUp` in generated clients and `sign_up` in `spacetime call` and +`describe`: ```typescript export const createEntity = spacetimedb.reducer( @@ -178,10 +185,27 @@ export const onConnect = spacetimedb.clientConnected((ctx) => { ... }); export const onDisconnect = spacetimedb.clientDisconnected((ctx) => { ... }); ``` -`ctx.connectionId` is `ConnectionId | null`, including in lifecycle contexts. Guard it before passing it to a helper or using it as a table key. +Connection hooks run once per connection. `ctx.connectionId` identifies that connection. +`ctx.sender` identifies the authenticated caller and stays the same when the client +reconnects with the same token. + +Use connection IDs for connection state, such as presence. A reload or network loss can +cause a disconnect. A disconnect alone does not mean the user signed out or their +application login expired. Keep connection cleanup separate from session revocation. + +`ctx.sender` is a SpacetimeDB identity, not necessarily an application account. Separate +identities can authenticate to the same application account. Identity equality alone +does not establish whether two callers belong to the same account. + +`ctx.connectionId` is typed `ConnectionId | null`. It is present inside connection lifecycle hooks and reducers invoked over a connection, and `null` in `init` and scheduled reducers. Guard it before passing it to a helper or using it as a table key. ## Reducer Context API +Each reducer call runs in one database transaction. An error that escapes the +reducer rolls back its database changes. `ctx.sender` identifies the caller; +application roles and permissions are not inferred from that identity. Table +visibility and view filters control reads, not authorization to call reducers. + `ctx` is the only source of sender identity, time, and randomness; stdlib clocks and RNG are unavailable in modules. Let exported callbacks infer their context type. In helpers, use `ReducerCtx>`; do not annotate a context as `any`, because that erases table row types and can make `bigint` expressions infer as `number`. ```typescript @@ -278,9 +302,22 @@ const Shape = t.enum('Shape', { A client subscribing to a view receives only the rows it returns. Use a per-user view (keyed on `ctx.sender`) for per-viewer access control: deleting a row it depends on (e.g. a membership row) automatically drops the rows it was exposing from that client. +Use index accessors in views. Do not scan a whole table with `.iter()` when an +indexed lookup can select the required rows. `t.row(...)` and `t.object(...)` return schema builders, not TypeScript runtime row types. Let a view callback infer its result, or annotate a separately declared structural type such as `Array<{ sku: bigint; label: string }>`. A named output type must not reuse the generated PascalCase name of its view accessor (for example, reserve `DiscountedProduct` for a `discounted_product` view). +A view context is `ViewCtx` (and `AnonymousViewCtx`), both exported from +`spacetimedb/server`. It carries `sender`, a read-only `db`, and `from`; it is +not a `ReducerCtx`, so a helper shared between a reducer and a view must accept +either: + +```typescript +import type { ReducerCtx, ViewCtx, InferSchema } from 'spacetimedb/server'; +type S = InferSchema; +function stockOf(ctx: ReducerCtx | ViewCtx, itemId: bigint) { ... } +``` + Both `spacetimedb.view(...)` and `spacetimedb.anonymousView(...)` take three arguments: view options, the declared return schema, and the callback. ```typescript @@ -288,7 +325,7 @@ Both `spacetimedb.view(...)` and `spacetimedb.anonymousView(...)` take three arg export const activeUsers = spacetimedb.anonymousView( { name: 'active_users', public: true }, t.array(entity.rowType), - (ctx) => [...ctx.db.entity.iter()].filter(e => e.active) + (ctx) => [...ctx.db.entity.active.filter(true)] // active: t.bool().index('btree') ); // Per-user view (varies by ctx.sender): diff --git a/tools/llm-sequential-upgrade/.gitignore b/tools/llm-sequential-upgrade/.gitignore index 14aa619a63d..35223d12b8f 100644 --- a/tools/llm-sequential-upgrade/.gitignore +++ b/tools/llm-sequential-upgrade/.gitignore @@ -27,4 +27,4 @@ telemetry/metrics.jsonl **/telemetry/**/metadata.json # Sequential-upgrade run output lives in the external spacetimedb-ai-test-results repo -sequential-upgrade/sequential-upgrade-*/ +sequential-upgrade/ diff --git a/tools/llm-sequential-upgrade/read-guard.sh b/tools/llm-sequential-upgrade/read-guard.sh new file mode 100644 index 00000000000..314c52e7cde --- /dev/null +++ b/tools/llm-sequential-upgrade/read-guard.sh @@ -0,0 +1,42 @@ +#!/usr/bin/env bash +# Write Claude Code settings that deny direct Read tool access to benchmark +# internals. Bash is allowed, so this is not filesystem isolation. + +write_read_guard() { + local app_dir="$1" backend="$2" out siblings="" + out="$app_dir/.read-guard-settings.json" + + local b + for b in spacetime postgres mongodb; do + [[ "$b" == "$backend" ]] && continue + siblings+=" \"Read(**/$b/results/**)\", +" + done + + cat > "$out" < tools/stack-bench/operator.env +``` + +In Windows PowerShell 5, replace `>` with `| Out-File -Encoding utf8`. +Then go to [provider credentials](#provider-credentials) for model work or +[validate the appliance](#validate-the-appliance) for model-free checks. +Do not repeat the image builds or setup below after a successful demo. + +For a new manual installation, build and prepare state as follows. +From the repository root: + +```sh +docker build --platform linux/amd64 -t stack-bench-build:local tools/stack-bench/container +docker build --platform linux/amd64 -f tools/stack-bench/appliance/Controller.Dockerfile -t stack-bench-controller:local . +docker run --rm --mount type=bind,source=/var/run/docker.sock,target=/var/run/docker.sock stack-bench-controller:local setup > tools/stack-bench/operator.env +``` + +The controller build exports the clean Git revision, builds the native binaries +and SDK, and records their source and checksums in the image. It does not consume +ignored host binaries. BuildKit caches the Rust target and package downloads. +The first build can take substantial time; complete it before the demo. + +Commands below are single lines so they can be pasted into PowerShell or a +POSIX shell. Docker must be running before `setup` or Compose commands. + +`setup` creates the state volume and directories, resolves both local images to +immutable content IDs, and writes a UTF-8 Compose environment file. It installs +the pinned PostgreSQL and MongoDB images when they are absent. It also installs +four prepared plans. It keeps existing plans and model credentials. Keep `operator.env` locally; it is ignored by Git. In Windows +PowerShell 5, use `| Out-File -Encoding utf8 tools/stack-bench/operator.env` instead +of `>` so the environment file is not UTF-16. + +### Provider credentials + +For a model-free check, no provider secret is needed. To configure model work, +write the subscription token through stdin: + +```sh +docker run --rm -i --mount type=volume,source=stack-bench-state,target=/state stack-bench-controller:local set-secret claude_subscription_token +``` + +Supply the token on stdin and close input. For API billing, use secret name +`anthropic_api_key` and set `STACK_BENCH_AGENT_AUTH=api-key` in `operator.env`. +The secret stays in a private volume file; it is not a command argument or +part of the environment file. The Docker socket is not needed by `set-secret`. +After pasting the token and pressing Enter, close stdin with Ctrl+D in a POSIX +terminal, or Ctrl+Z followed by Enter in Windows PowerShell. + +Run the remaining commands from `tools/stack-bench`. Compose uses the state +volume's results directory as its working directory, so `plans/...` and +`campaigns/...` refer to durable state inside Docker. + +### OpenAI credentials + +Select the `codex` agent adapter and an explicit billing mode in `operator.env`: + +- `STACK_BENCH_AGENT_AUTH=openai-api-key` uses + `STACK_BENCH_OPENAI_API_KEY_FILE`. Store the key with `set-secret openai_api_key`. +- `STACK_BENCH_AGENT_AUTH=openai-account` uses `STACK_BENCH_CODEX_AUTH_FILE`. + Use `codex login` with file credential storage, then send only its `auth.json` + through standard input to `set-secret codex_auth`. Do not copy your Codex home. + +Setup writes the two file paths below the state volume's `secrets` directory. +Use the same Docker `set-secret` command shown above with the selected secret name. +API usage and account plan usage are separate billing modes. There is no fallback +from an account to an API key. See the [official authentication documentation](https://learn.chatgpt.com/docs/auth). + +Account mode takes an access-token snapshot in the trusted controller. Neither +the login file nor its refresh token reaches generated commands. This version +does not refresh account tokens. An expired token fails before coding starts; +expiry during a request stops that request as a provider failure. Log in again +and replace the stored file before another attempt. +OpenAI receipts use observed tokens and the plan's frozen rates. They are a +comparison cost, not an account-plan invoice. Use rates that cover the selected +model and context range. The initial broker supports text and local function +or custom tools. It rejects hosted tools, images, remote files, stored prompts, +and server-side conversation references because these need other cost bounds. + +Rebuild the build image to include the pinned Codex CLI before using this adapter. +The local mock check verified the CLI request and usage stream, not live account +access. The pinned CLI reports missing model metadata and uses fallback settings +for the selected model. Confirm those settings in a qualification run before +using this adapter for a published comparison. + +Account mode supports `gpt-5.3-codex`, `gpt-5.4`, `gpt-5.4-2026-03-05`, +`gpt-5.6-sol`, and `gpt-6-astra`. +The broker reserves each request against the documented 128,000-token output +bound. Unknown account models fail before a provider request. API mode uses an +explicit `max_output_tokens` limit. Both modes still require explicit campaign +pricing. See the [GPT-5.3-Codex model limits](https://developers.openai.com/api/docs/models/gpt-5.3-codex) +and [GPT-5.4 model limits](https://developers.openai.com/api/docs/models/gpt-5.4). + +### OpenRouter credentials and routing + +Select the `openrouter` adapter. It uses the same Codex coding runtime as the +`codex` adapter. Store its API key with `set-secret openrouter_api_key`, then set +`STACK_BENCH_AGENT_AUTH=openrouter-api-key` and +`STACK_BENCH_OPENROUTER_API_KEY_FILE` in `operator.env`. + +Each campaign agent selection must fix `model`, `providerRoute`, and `maxOutputTokens`, for example: + +```json +{ "adapter": "openrouter", "adapterVersion": "1.0.0", + "model": "openai/gpt-5.3-codex", "providerRoute": "openai", "maxOutputTokens": 8192 } +``` + +The example identifies a model and route; it is not live qualification evidence. +Use a model with Responses API and local tool support. The broker fixes one provider route, disables fallback, and rejects route changes +during continuation. A base provider slug can include several endpoint variants; +use a specific endpoint slug when that distinction matters. Receipts retain the +provider reported by OpenRouter. +See [OpenRouter routing](https://openrouter.ai/docs/guides/routing/provider-selection) +and the [Responses API](https://openrouter.ai/docs/api/reference/responses/overview). + +Use `--agent-adapter openrouter --provider-route openai --max-output-tokens 8192` +for standalone preflight. +Preflight checks local setup and credentials without a provider request. + +Set the output token limit within the selected model endpoint's documented cap +and the broker's 128,000-token safety cap. This is a per-request bound. +Declare token price ceilings and a cost limit in the campaign. The broker sets +routing price limits, rejects request fees, and records reported `usage.cost`. +These receipts are OpenRouter charges, not costs inferred from token counts. +Missing cost evidence cannot produce an exact receipt. API key billing is the +supported mode; account subscriptions and BYOK are not supported. +Rebuild the coding and controller images before use. Mock tests do not prove +live model access or model quality; qualify the selected model and endpoint +before publishing comparisons. + +## Validate the appliance + +Run commands from `tools/stack-bench` on the runner. + +Check the Compose configuration: + +```sh +docker compose --env-file operator.env -f appliance/docker-compose.yaml config --quiet +``` + +Run preflight for the exact planned scope: + +```sh +docker compose --env-file operator.env -f appliance/docker-compose.yaml run --rm controller preflight --backend spacetime,postgres,mongodb --track ecommerce --levels 1 --run-index 0 --agent-adapter reference-fixture --guidance neutral +``` + +This preflight selects the model-free reference adapter and needs no provider +credentials. For model work, use the planned agent adapter and its configured +credential. This preflight verifies the runner, images, dependencies, ports, +and storage without creating an attempt. Each campaign attempt then runs its +own smoke check inside its activated private network, before the agent starts. +Standalone appliance preflight is read-only. The reference trial below exercises +the automatic smoke checks without model calls. + +## Check the delivered runtime + +This command starts real containers and grades the shipped reference app. It +makes no model calls. Run it before collecting model results: + +```sh +docker compose --env-file operator.env -f appliance/docker-compose.yaml run --rm controller campaign trial plans/reference-check.json --out campaigns/reference-check +``` + +Inspect its status and evidence before using the appliance for model work. +A reference fixture pass checks the runtime path; it is not evidence that an +agent implemented the product. + +## Inspect a campaign + +To correct grading after a grader fix, use the saved execution in a separate +output directory. This runs no coding agent and has no provider cost: + +```sh +docker compose --env-file operator.env -f appliance/docker-compose.yaml run --rm controller run --grade-from campaigns/example/attempts/attempt-id/execution-1 --out regrades/attempt-id +``` + +This path accepts a completed single-level sequential run. It verifies the +source checkpoint, keeps the original check scope and account aliases, and +rejects changes to the product request or contract. Use the original build +image and dependency bundle. Startup must reproduce the saved source without +changes. Repeat `--check ` to regrade only affected checks from +the original scope. The separate `regrade.json`, grading bundle, and cleanup evidence do +not replace the original run or create another build sample. For saved dependency +candidates, select `--grade-level` and affected checks as described in the +[dependency replay method](../docs/grading-coverage.md#replay-a-saved-dependency-candidate). +An interrupted dependency run can replay an earlier candidate only after authenticated +recovery proves cleanup and that candidate has its complete source-bound grade bundle. +The diagnostic preserves the interrupted parent status; it does not finish the campaign. + +The campaign file is the run authority. Store it below +`plans/` in the state volume. + +`setup` installs `plans/paid-l1.json` from the supplied +[`campaign.paid-l1.json`](campaign.paid-l1.json), binds it to the local controller +and build image IDs, and freezes it for execution. It runs one fresh L1 build per stack, +three in parallel, with no repairs or retries and a $10 limit per attempt +($30 maximum across the three attempts). It uses Sonnet 5 and includes the +SpacetimeDB skills. Its results are provisional. The example already sets +`parallelism: 3`; change a draft and freeze it before execution if needed. +Inspect its model, stacks, repetitions, spend limits, and pricing before launch. +For a longer study, [`campaign.paid-l1-l3.json`](campaign.paid-l1-l3.json) is a +draft three-stack progression pilot. It selects L1 through L3, six repairs total +per attempt, no execution retries, a 120-minute attempt limit, and a $30 +per-attempt cap ($90 maximum). These are proposed limits, not a cost estimate. +It must be bound to the selected image identities, frozen, and installed under +`plans/` before execution; setup does not install it automatically. Earlier +levels must pass before later levels start. See the +[research roadmap](../docs/research-roadmap.md) for collection and analysis rules. +`appliance/campaign.example.json` is a model-free reference plan; changing its +title does not make it a coding-agent campaign. + +Use a new manifest ID and output directory for a new comparison. Do not edit a +running campaign's plan. Setup preserves an existing `paid-l1.json`; it does not +silently replace or rebind it after an image rebuild. A frozen plan copied from +another machine binds that machine's image identities and cannot run unchanged. + +Compile and inspect it without model work: + +```sh +docker compose --env-file operator.env -f appliance/docker-compose.yaml run --rm controller campaign show plans/paid-l1.json +``` + +A test plan selects the model, stacks, work, checks, budgets, repetitions, +parallelism, pricing, controller image, and build image. When the run starts, +Stack Bench records these settings with the results. This prevents settings +from changing during a campaign. + +The manifest also defines how repair work is selected and limited: + +```json +"repair": { "selection": "feature", "budget": { "perFeature": 1 } } +``` + +Dependency mode supports `feature` or `batch` selection. The budget must name +at least one limit; each is a non-negative integer with no upper cap: + +- `total`: repairs across the whole attempt. `0` runs the initial grade and + advances passed branches without any repair. +- `perFeature`: repairs that may include one feature. +- `perDepth`: `{ "count": N, "carry": true | false }`. Each opened depth adds + `count` repairs; `carry` keeps unused depth repairs available later. + +When several features have failed, the next repair goes to the first of them +by dependency depth, then by `order`: + +- `declared` (default): the order the catalog declares its features, which is + part of the catalog's identity. +- `shuffled`: a permutation within each depth drawn once from the campaign's + `ordering.seed` when the plan compiles, frozen in the plan as the policy's + `nodeOrder`, and used by every stack in the campaign. The catalog and its + qualification are unchanged; the policy identity carries the order. +When limits are combined, the tightest remaining limit wins, and the result +names which one stopped a feature: `feature-repairs-exhausted`, +`depth-repairs-exhausted`, `total-repairs-exhausted`, or `repeated-findings` +when the same failures reach the configured observation count. The initial +failure counts as one; each completed repair with the same failures adds one. +Set `mode.unchangedFailureLimit` to a positive integer (default 3). To allow +five repairs even when all fail identically, set it to 6. A completed +repair counts even when its grade did not finish; its source is kept beside +the run and graded on resume before any further coding session. Sequential +mode requires `batch` selection and one `total` limit. + +The plan, dashboard, and report show qualification status. Publish scores as +verified comparison data only after every selected level is qualified. + +`plans/reference-check.json` is the shipped zero-cost reference check. It uses +the reference adapter included in the controller image. `plans/ecommerce-progression.json` +keeps the full rigorous workload for reference validation; the short check does +not replace that workload. Both use hand-written reference apps and produce no +comparative model data. + +## Run a campaign + +Start the campaign. This command creates the run state and records the exact +test plan automatically: + +```sh +docker compose --env-file operator.env -f appliance/docker-compose.yaml run --rm controller campaign run plans/paid-l1.json --out campaigns/campaign-001 +``` + +The campaign controls attempt counts and concurrency. `repetitions` sets the +default attempt count per stack. A stack can override it. `parallelism` limits +simultaneous attempts. Each live attempt receives isolated ports, database +names, locks, workspaces, and evidence paths. + +Coding, backend, browser, and broker containers share only their attempt's +private network namespace. Native firewall rules block host and other-attempt +connections. Concurrent native attempts and exact cleanup have passed the +bounded Docker checks. A clean appliance rehearsal remains a release gate. + +Set each plan's `parallelism` to the number of simultaneous attempts you want. +Admission automatically leases unused run indices and host ports across campaigns. +It reserves only each dispatched attempt's stack and releases the reservation after +verified cleanup. [Jobs](../docs/execution-jobs.md) select explicit capacity wait/fail +policy; requested parallelism never changes. No worker-pool setting is needed. The startup baseline +remains 4 CPUs and 8 GiB RAM. Preflight reports the requested campaign's +container caps and warns when their sum exceeds Docker's total allocation. +These caps do not reserve CPU or RAM and are not measured hardware minimums. + +Each worker has a 2-CPU/4-GiB coding container, a 1-CPU/1-GiB backend, a +1-CPU/2-GiB browser, and a broker capped at 256 MiB when needed. Thus nine +workers have known caps totaling 36 CPUs and 65.25 GiB RAM. Broker CPU, +controller processes, the package cache, and Docker need additional resources. + +The shared package cache has caps of 1 CPU, 2 GiB RAM, and 128 processes. Allow +for its use alongside the controller and attempt containers. + +Docker's reported memory is total allocation, not free memory. Contention can +increase run time; heavier apps can exhaust memory. Validate the intended parallelism with the selected workload. A short fixture +test does not establish capacity for arbitrary model builds or timed grading. + +The 10-GiB disk check is a startup free-space check, not a per-worker reservation +or a storage quota. Concurrent installs, app builds, and retained evidence share +that storage. Keep space for their growth and for shared services. + +An attempt holds its worker from its first build through its final grade and +cleanup. Results remain provisional until their grading qualification is current. + +The remaining `campaign` snippets are controller subcommands. Run them after +the same Docker Compose `run --rm controller` prefix used above. + +Use durable state for normal control: + +```sh +campaign status +campaign stop +campaign inspect +campaign report +``` + +- `status` is the compact normal view. +- `stop` stops owned active work and retains its state and evidence. +- `inspect` adds score, cost, duration, cleanup, evidence, and feature progress. +- `report` rebuilds `report/report.json` and `report/report.html` from retained + evidence. + +Stop interrupts active attempts. A stopped sequential attempt remains invalid. +Running the same trial again starts only pending attempts; it does not restart +the interrupted attempt. Resume starts scheduled dependency work. + +Do not infer state from logs. Use logs only to diagnose a reported phase or +failure. Automatic retries are limited by the manifest +`attemptPolicy`. Additional repair grants and budget extensions require an +explicit operator action. + +## Resume and repair + +For a live provider wait, inspect the current execution: + +```sh +campaign continuation-status --attempt --json +campaign continue-provider --attempt --request-id +``` + +Use these commands through the controller, as with other campaign commands. +The second command authorizes one continuation of the current waiting session. +Fix the provider account first. Reusing a request ID for the same wait is +idempotent. An ID from an earlier wait cannot authorize a later wait. + +The wait keeps the app, database, candidate source, native session, and parallel +slot. Database clocks and background processes still run. Waiting consumes the +existing time allowance; `grant-time` can extend it separately. Continuation does +not add repairs, increase the cost limit, or change the provider, model, billing +mode, or task. All invocation receipts, wait events, and acceptance records stay +under the execution's `provider-waits` directory. +Reports read these events even when a killed process has no final agent result. +If no wait-end event exists, the last heartbeat gives a lower bound on wait time. + +The command works only while the original controller and execution remain live. +Cancellation, timeout, stale heartbeat, lost resources, or failed native-session +validation ends eligibility. A stopped historical execution cannot be restored +by this command. The current candidate is not graded during a provider wait. + +Add time to a running attempt without restarting its agent: + +```sh +campaign grant-time --attempt --grant-id --minutes 120 +``` + +This adds two hours to the existing limit. It does not change the frozen plan, +cost limit, or repair allowance. Reuse the same grant ID and minutes after an +uncertain response; a new ID requests more time. The request is pending until +the owning controller accepts it. The attempt page shows the effective limit +and the request status. Its **Add time** control uses the same operation. + +Only controllers built with time-grant support can accept live requests. +Do not replace a running controller to install this feature. A time grant does +not restart an expired attempt by itself. A stopped attempt can receive a grant +only at a verified completed-depth checkpoint, before the next build starts. +Interrupted coding and grading are not supported. Use the existing +`campaign resume --out ` command after the +grant. The dashboard combines these steps with **Add time and resume** only for +an eligible checkpoint. It shows the reason when continuation is not safe. +Source files alone do not restore an interrupted agent. + +The initial limit comes from `budgets.attemptTimeoutMinutes` in the frozen +plan. The Plans table shows it in hours and minutes. It includes coding, +grading, repairs, and host sleep, except for a verified planned depth pause. +Grant records retain the original limit and +each accepted extension; adding time alone does not invalidate efficacy data. + +If the controller stopped while an attempt remained live, reconcile ownership +before any resume: + +```sh +campaign reconcile --out +``` + +Reconciliation changes state only when private supervisor evidence proves that +the exact owned resources are clean. It does not restore an interrupted +database or agent session. Do not remove a worker claim or alter completion and +cost records to bypass continuation checks. + +Dependency campaigns can grant more repairs to selected exhausted features: + +```sh +campaign grant-repairs --attempt --grant-id --level --feature --repairs +``` + +The grant creates a linked continuation. It does not rewrite the completed +execution. Use `campaign resume --out ` to +run scheduled dependency work. + +## Continue to a higher level + +To keep the same live execution, select the full target before launch and use a +[planned depth pause](../README.md#pause-before-a-later-depth). The controller +must remain running. This differs from the source-seeded method below. + +Use a separate source-seeded campaign to continue a completed dependency campaign. +For example, prepare an L3 campaign from its passed L2 source without starting work: + +```sh +campaign extend --from --depth 2 --out --prepare-only +``` + +Preparation copies and verifies each source checkpoint and records its parent. +It makes no model calls and starts no attempts. After review, start the prepared +campaign with `campaign run --out `. +Without `--prepare-only`, `extend` prepares and starts the campaign immediately. + +Every matching parent attempt must be complete and pass the chosen depth. +The target must use progressive dependency work and include that depth plus a +higher depth. Stack, model, repetition, guidance, and repair condition must match. +Earlier levels are regraded without model work before any upgrade. If validation +fails, that attempt stops before higher-level work. + +This preserves source, not the agent session or database runtime. The new campaign +has its own time, cost, and repair budgets. Its reported cost excludes parent work; +reports identify the parent and label the result as a seeded continuation. Add +the parent cost when measuring the full path. Previously taught repairs remain in +the source, so this cannot turn a repaired app into an unaided first-build result. +Other target-definition changes require a separate comparison interpretation; this +is not evidence of an uninterrupted run under unchanged conditions. + +## Model-free trials and qualification + +`campaign trial` accepts only registered non-billable adapters and zero pricing. +It validates orchestration but does not produce comparative model data. + +Check qualification requirements without starting work: + +```sh +docker compose --env-file operator.env -f appliance/docker-compose.yaml run --rm controller qualification status --track ecommerce --level --recipe +``` + +Run only evidence required by that exact status. Do not repeat reference, +mutation, or null work when its bound inputs have not changed. See the +[reference app guide](../reference-apps/README.md) and +[grader guide](../grader/README.md) for qualification rules. +Use the recipe from the compiled plan; sequential levels and dependency depths +can select different checks. Passing source tests or one reference trial does +not qualify the full scope. Pending qualification permits provisional campaigns, +but blocks verified comparison claims. + +## Dashboard + +Start the optional dashboard: + +```sh +docker compose --env-file operator.env -f appliance/docker-compose.yaml --profile dashboard up -d dashboard +``` + +Open `http://127.0.0.1:7331`. The dashboard reads the same campaign state as the +CLI. Reading results does not require provider credentials. Run controls launch +the Compose controller and check provider configuration at launch. + +Run controls work directly in the local browser. There is no dashboard password +to retrieve. Same-origin and browser-token checks protect control requests. +The dashboard is for a trusted local machine; do not expose it on a shared network. +Model credentials are configured separately. + +See [dashboard/README.md](../dashboard/README.md). + +## Results and cleanup + +Results remain in the `stack-bench-state` Docker volume after the controller exits. +Verify and copy the complete campaign package before deleting the runner. + +For example, export the completed `campaign-001` to the host. Run from +`tools/stack-bench`; first create an empty local `results` directory if needed. +These commands copy evidence and remove only the temporary transfer container: + +```sh +docker compose --env-file operator.env -f appliance/docker-compose.yaml run --rm controller campaign report campaigns/campaign-001 +docker create --name stack-bench-result-transfer --mount type=volume,source=stack-bench-state,target=/state,readonly stack-bench-controller:local --help +docker cp stack-bench-result-transfer:/state/results/campaigns/campaign-001 results/campaign-001 +docker rm stack-bench-result-transfer +``` + +Open `results/campaign-001/report/report.html` in a browser, or use the dashboard +to inspect checks, screenshots, logs, and cost evidence. The copied files remain +available when Docker is stopped. + +To prepare a smaller research pack, use +`campaign export campaigns/campaign-001 --out exports/campaign-001` in the +controller. The destination parent must already exist; the destination itself +must be new and outside the campaign directory. The export contains the report, +attempt/execution CSV tables, and indexed public artifacts with verified hashes. +It is a partial copy: source, transcripts, media, and external evidence are +omitted, so links to those files do not work offline. Review free text before +sharing. Keep the complete original campaign as the durable internal archive. + +A run removes only resources whose private ownership evidence still matches. +If cleanup cannot be proved, it preserves the evidence and quarantines the run. +Follow [RECOVERY.md](RECOVERY.md). Do not delete same-name resources or clear the +shared state root by guesswork. + +Workspace cleanup requires the owned build container to remain running until +the controller stops its application processes and restores directory permissions. +Normal run completion then removes the temporary work directory. Early aborts +and interruptions retain that directory for inspection, with controller access +restored when handback succeeds. Preserve needed files before an operator removes +the exact retained directory. The controller does not sweep retained work. +If that container exits, runs out of memory, or is removed before handback, cleanup +retains the private lease and reports the failure. Preserve the result package +and private recovery state. For a stopped container, diagnose the exit and restore +that exact container before retrying authenticated recovery. A container removed +before handback requires manual workspace ownership repair; automatic recovery +continues to refuse because it cannot prove the handback. No background sweep +repairs this condition. diff --git a/tools/stack-bench/appliance/RECOVERY.md b/tools/stack-bench/appliance/RECOVERY.md new file mode 100644 index 00000000000..246ac0e968f --- /dev/null +++ b/tools/stack-bench/appliance/RECOVERY.md @@ -0,0 +1,91 @@ +# Interruption and recovery + +Recovery here means authenticated cleanup and state reconciliation. It does not +restore a database snapshot or restart an interrupted agent session. A planned +[depth pause](../README.md#pause-before-a-later-depth) retains live processes and +requires the original controller to stay running. After controller loss, +`continue-depth` refuses release and keeps the pause evidence unchanged. + +Stack Bench never guesses that a container, listener, lock, database, or data +directory is safe to delete. Normal teardown authenticates the run's private +lease, compares exact owned container and network IDs, and releases only locks +whose owner record still matches that lease. + +Paths below are inside the Docker state volume. Replace `` with +the exact `STACK_BENCH_STATE_ROOT` value written by setup in `operator.env`. +Run Compose commands from `tools/stack-bench`. The host does not need that +Linux directory. Compose mounts the state volume at the recorded path. + +Every appliance run keeps two different records: + +- `results/.../recovery.json` is public, contains no ownership token, and says + whether cleanup is `clean`, intentionally `retained`, or `quarantined`; +- `/controller-home/supervisor/.json` is private recovery authority for a standalone run. It + contains the lease token and must remain readable only by the appliance + operator. Normal cleanup deletes it. Refused cleanup deliberately preserves + it. + +Campaign supervisor records are under that campaign's `.private` directory. +For an interrupted campaign, first use the campaign recovery path: + +```sh +docker compose --env-file operator.env -f appliance/docker-compose.yaml run --rm controller \ + campaign reconcile plans/campaign.json --out campaigns/campaign-001 +``` + +Use the campaign's original plan and output directory. Reconciliation checks +private child authority before it releases reservations or changes campaign +state. The direct commands below are for a specific retained supervisor or +lease path reported by the run. + +## If a run is interrupted + +1. Preserve the result directory and private supervisor-state file. +2. Read `recovery.json`. Do not publish an attempt whose status is + `quarantined`. +3. Do not start another run using any lock key listed in that artifact. +4. Retry authenticated cleanup from the controller: + +```sh +docker compose --env-file operator.env \ + -f appliance/docker-compose.yaml run --rm controller \ + recover /controller-home/supervisor/.json +``` + +On success the command changes `recovery.json` to `clean`, releases the exact +owned resources, and removes the private supervisor state. It is idempotent +when public lease evidence already proves that an earlier cleanup completed. + +If the parent process ended before it retained a supervisor file, recover from +the private runtime lease instead. Supply a durable output directory outside +the private runtime directory: + +```sh +docker compose --env-file operator.env \ + -f appliance/docker-compose.yaml run --rm controller \ + recover-lease /controller-home/runtime//backend-lease.json \ + --out /results/recovery/ +``` + +This path uses the same ownership token, container ID, network ID, and lock +checks. It refuses an output directory inside the runtime directory because a +successful recovery removes that directory. + +## If recovery refuses + +Refusal is the safety behavior. It means a live resource does not match the +lease or its identity could not be proven. The command leaves the private state, +lease, lock records, and public quarantine artifact intact. + +Compare the live container and network IDs with `recovery.json` and the +private lease before manual action. Never delete a same-name container, kill a +port's current listener, remove another lock, or recursively clear the shared +state root merely because its name resembles Stack Bench. Escalate with the +complete result directory and private state stored separately from public +artifacts. + +## Intentional retention + +`--retain-backend` is inspection mode, not successful cleanup. It writes +`status: "retained"` and preserves private recovery authority. No other run may +reuse the listed locks until the recovery command completes. diff --git a/tools/stack-bench/appliance/RELEASE.md b/tools/stack-bench/appliance/RELEASE.md new file mode 100644 index 00000000000..552d033125a --- /dev/null +++ b/tools/stack-bench/appliance/RELEASE.md @@ -0,0 +1,125 @@ +# Release assembly and verification + +Stack Bench uses two deliberately different release states. + +- A `candidate` has exact image digests, checksummed files, and digest-bound + SPDX SBOMs. It is useful for inspecting and testing a proposed bundle, but it + is unsigned and cannot be called qualified. +- A `qualified` release adds a bundled public key, a detached Sigstore bundle + covering `release.json`, and registry signatures for every image. Verification + must use a public key obtained outside the release bundle. + +Schema v2 is the only accepted release format. + +## Build from the delivered branch + +Use a clean normal clone. The Docker build exports canonical Git content and +checks the checkout with the existing release-source and binary-source identity +code. It builds the controller, SDK, and native binaries without host Node or +Rust and without ignored binary files: + +```sh +docker build --platform linux/amd64 -t stack-bench-build:local tools/stack-bench/container +docker build --platform linux/amd64 -f tools/stack-bench/appliance/Controller.Dockerfile -t stack-bench-controller:local . +``` + +The controller contains `/opt/stack-bench/source-identity.json` and generated +`container/spacetimedb-binaries.json`. These bind the clean source revision and +native binary checksums. Setup resolves local image tags to immutable content +IDs before use. Rebuilding a tag does not change an already prepared run. + +The optional `container/build-linux-cli.sh` exports binaries through the same +Dockerfile's `binary-export` target. It is for maintainers who need loose files; +it is not a prerequisite for building the appliance. + +A branch build is a local candidate. It does not need registry publication, +Cosign, SBOM assembly, or a qualified release manifest to run provisional data. +The signed distribution path below remains a separate publication gate. + +## Build a candidate + +Publish the first-party images, resolve every first- and third-party image to an +exact single-platform `linux/amd64` manifest reference, then generate one SPDX +SBOM for each exact reference. Do not use a multi-architecture index digest: +Docker Scout correctly reports the selected child-manifest digest, so an index +digest cannot satisfy the one-image/one-SBOM identity contract. + +```sh +node dist/src/releases/release-bundle.js sbom registry.example/controller@sha256:DIGEST \ + --output bundle/sbom/controller.spdx.json +``` + +The command uses registry resolution, refuses mutable references and existing +output, and checks that Docker Scout's SPDX 2.3 document contains the requested +image digest. A successful tool exit without that digest binding is rejected. + +Create a strict release specification with `state: "candidate"`, +`signing: null`, and `files` entries containing only `path` and `role`. Place +every input below the bundle root, then materialize immutable size and SHA-256 +metadata: + +```sh +node dist/src/releases/release-bundle.js assemble release-spec.json \ + --root bundle --output bundle/release.json +node dist/src/releases/release-manifest.js verify bundle/release.json --root bundle +``` + +Candidate verification reports `candidate-file-integrity`. It validates all +declared files and all five image-to-SBOM digest bindings. Candidate manifests +must use `signing: null` and cannot include a public signing key. + +## Sign and qualify + +Signing keys are external CI inputs. Never copy a private key, registry token, +or signing password into the source tree, image, bundle, Compose environment, +or command transcript. Sign each exact registry image with Cosign. The +authoritative image-signature evidence stays attached to the registry object +and is checked directly during verification; the release does not preserve a +redundant unverified export. Add the public half of the signing key as +`signing/cosign.pub` with the `public-key` role. + +Change the specification to `state: "qualified"` and declare: + +```json +{ + "signing": { + "scheme": "cosign-public-key-v1", + "publicKeyPath": "signing/cosign.pub", + "manifestBundlePath": "signing/release-manifest.sigstore.json" + } +} +``` + +Assemble `release.json` only after all other evidence exists, then sign that +exact file with a detached Cosign bundle: + +```sh +cosign sign-blob --yes --key "$COSIGN_KEY" \ + --bundle bundle/signing/release-manifest.sigstore.json bundle/release.json +``` + +The detached bundle is intentionally not checksummed by `release.json`: a file +cannot contain the hash of its own signature. Cosign authenticates it instead. + +Verify with the trusted public key copied to a path outside the downloaded +bundle: + +```sh +node dist/src/releases/release-manifest.js verify bundle/release.json --root bundle \ + --trusted-key /operator/trust/stack-bench-cosign.pub +``` + +Qualified verification refuses an absent or bundle-local trust key, requires +it to equal the public key bound by the signed manifest, verifies the detached +manifest signature, and runs `cosign verify` against every exact registry image +reference. A failed or unavailable Cosign invocation is a failed release; there +is no downgrade to candidate verification. The controller image includes +checksum-pinned Cosign 3.1.3 so this command is available in the delivered +appliance rather than depending on an untracked host installation. + +## Trust distribution + +The release bundle cannot establish trust in its own key. Publish the expected +public key and its SHA-256 fingerprint through a separately controlled channel. +The operator must compare that fingerprint before verification. Key rotation +requires a new release and an explicit trust-distribution update. diff --git a/tools/stack-bench/appliance/campaign.demo.json b/tools/stack-bench/appliance/campaign.demo.json new file mode 100644 index 00000000000..d98f7a79840 --- /dev/null +++ b/tools/stack-bench/appliance/campaign.demo.json @@ -0,0 +1,150 @@ +{ + "schemaVersion": 8, + "kind": "campaign-manifest", + "id": "demo", + "version": "1.0.0", + "state": "draft", + "title": "Model-free three-stack demo: selected L1 checks", + "track": "ecommerce", + "mode": { + "id": "sequential" + }, + "repair": { + "selection": "batch", + "budget": { + "total": 0 + } + }, + "levels": [ + 1 + ], + "selection": { + "levels": [ + { + "level": 1, + "recipe": "ecommerce.sequential-l1", + "features": [ + "ecommerce.feature.accounts", + "ecommerce.feature.cart-checkout", + "ecommerce.feature.catalog-items", + "ecommerce.feature.catalog-discovery", + "ecommerce.feature.purchasing", + "ecommerce.feature.reviews", + "ecommerce.feature.warehouse-admin" + ], + "checks": [ + "ecommerce.feature.accounts.accounts.1a", + "ecommerce.spec.concurrency-safety.duplicate-checkout.203b", + "ecommerce.spec.access-control.review-eligibility.108a", + "ecommerce.spec.access-control.review-eligibility.108b", + "ecommerce.spec.transactional-integrity.unique-review.6b", + "ecommerce.spec.access-control.warehouse-area-boundary.7a", + "ecommerce.feature.cart-checkout.cart.4d", + "ecommerce.spec.access-control.signed-out-purchase.3a", + "ecommerce.spec.concurrency-safety.stock-limit.3d" + ] + } + ] + }, + "stacks": [ + { + "id": "spacetime", + "adapterVersion": "1.4.0" + }, + { + "id": "postgres", + "adapterVersion": "1.6.0" + }, + { + "id": "mongodb", + "adapterVersion": "1.5.0" + } + ], + "agents": [ + { + "adapter": "reference-fixture", + "adapterVersion": "1.4.0", + "model": "reference-fixture" + } + ], + "conditions": [ + { + "id": "product-request", + "guidanceProfile": "neutral", + "repairPolicy": "scored-only", + "specifications": { + "levels": [ + { + "level": 1, + "requested": [], + "expected": [ + "ecommerce.spec.access-control", + "ecommerce.spec.concurrency-safety", + "ecommerce.spec.external-data-sync", + "ecommerce.spec.live-state", + "ecommerce.spec.state-durability", + "ecommerce.spec.transactional-integrity" + ], + "observed": [] + } + ] + } + } + ], + "repetitions": 1, + "parallelism": 3, + "ordering": { + "method": "balanced-rotation", + "seed": "demo-v1" + }, + "budgets": { + "attemptTimeoutMinutes": 20, + "maxCostUsdPerAttempt": null + }, + "attemptPolicy": { + "retries": 0, + "retryOn": [], + "excludeFromAnalysis": [ + "contaminated", + "harness_failure", + "inconclusive", + "ungraded", + "provider_failure" + ] + }, + "runtime": { + "releaseManifestSha256": null, + "controllerImage": null, + "buildImage": null, + "platform": "linux/amd64" + }, + "pricing": { + "currency": "USD", + "unit": "USD-per-million-tokens", + "capturedAt": "2026-08-12T00:00:00Z", + "source": "reference fixture adapter makes no billable provider calls", + "models": { + "reference-fixture": { + "input": 0, + "output": 0, + "cacheWrite5m": 0, + "cacheWrite1h": 0, + "cacheRead": 0 + } + } + }, + "analysis": { + "primaryMetric": "checkCompletionRate", + "secondaryMetrics": [ + "totalCostUsd", + "totalTokens", + "firstBuildScoreRate", + "totalDurationMs", + "invalidAttemptRate" + ], + "dispersion": "median-iqr", + "invalidAttempts": "report-separately", + "missingData": "no-imputation", + "comparisonUnit": "stack-agent-condition-recipe" + } +} diff --git a/tools/stack-bench/appliance/campaign.ecommerce-progression-reference.json b/tools/stack-bench/appliance/campaign.ecommerce-progression-reference.json new file mode 100644 index 00000000000..48e1ae4e3b5 --- /dev/null +++ b/tools/stack-bench/appliance/campaign.ecommerce-progression-reference.json @@ -0,0 +1,95 @@ +{ + "schemaVersion": 8, + "kind": "campaign-manifest", + "id": "ecommerce-progression-reference", + "version": "2.0.1", + "state": "draft", + "title": "Ecommerce progression reference pilot", + "track": "ecommerce", + "mode": { "id": "dependency", "workSelection": "progressive" }, + "repair": { "selection": "feature", "budget": { "total": 0 } }, + "levels": [1, 2, 3, 4, 5, 6], + "featureCatalog": "progression/ecommerce.json", + "selection": { + "levels": [ + { "level": 1, "recipe": "ecommerce.progression-catalog" }, + { "level": 2, "recipe": "ecommerce.progression-catalog" }, + { "level": 3, "recipe": "ecommerce.progression-catalog" }, + { "level": 4, "recipe": "ecommerce.progression-catalog" }, + { "level": 5, "recipe": "ecommerce.progression-catalog" }, + { "level": 6, "recipe": "ecommerce.progression-catalog" } + ] + }, + "stacks": [ + { "id": "mongodb", "adapterVersion": "1.5.0" }, + { "id": "postgres", "adapterVersion": "1.6.0" }, + { "id": "spacetime", "adapterVersion": "1.4.0" } + ], + "agents": [ + { + "adapter": "reference-fixture", + "adapterVersion": "1.4.0", + "model": "reference-fixture" + } + ], + "conditions": [ + { + "id": "reference-pilot", + "guidanceProfile": "neutral", + "repairPolicy": "scored-only" + } + ], + "repetitions": 1, + "parallelism": 1, + "ordering": { + "method": "balanced-rotation", + "seed": "ecommerce-progression-reference-1" + }, + "budgets": { + "attemptTimeoutMinutes": 180, + "maxCostUsdPerAttempt": null + }, + "attemptPolicy": { + "retries": 0, + "retryOn": [], + "excludeFromAnalysis": [ + "contaminated", + "harness_failure", + "inconclusive", + "ungraded" + ] + }, + "runtime": { + "releaseManifestSha256": null, + "controllerImage": null, + "buildImage": null, + "platform": "linux/amd64" + }, + "pricing": { + "currency": "USD", + "unit": "USD-per-million-tokens", + "capturedAt": "2026-08-25T00:00:00.000Z", + "source": "Reference fixtures make no provider calls.", + "models": { + "reference-fixture": { + "input": 0, + "output": 0, + "cacheWrite5m": 0, + "cacheWrite1h": 0, + "cacheRead": 0 + } + } + }, + "analysis": { + "primaryMetric": "finalScoreRate", + "secondaryMetrics": [ + "firstBuildScoreRate", + "totalDurationMs", + "invalidAttemptRate" + ], + "dispersion": "median-iqr", + "invalidAttempts": "report-separately", + "missingData": "no-imputation", + "comparisonUnit": "stack-agent-condition-recipe" + } +} diff --git a/tools/stack-bench/appliance/campaign.example.json b/tools/stack-bench/appliance/campaign.example.json new file mode 100644 index 00000000000..29bed19f541 --- /dev/null +++ b/tools/stack-bench/appliance/campaign.example.json @@ -0,0 +1,140 @@ +{ + "schemaVersion": 8, + "kind": "campaign-manifest", + "id": "ecommerce-l1-reference-check", + "version": "2.0.0", + "state": "draft", + "title": "Ecommerce L1 model-free appliance check", + "track": "ecommerce", + "mode": { + "id": "sequential" + }, + "repair": { + "selection": "batch", + "budget": { + "total": 0 + } + }, + "levels": [ + 1 + ], + "selection": { + "levels": [ + { + "level": 1, + "recipe": "ecommerce.sequential-l1", + "features": [ + "ecommerce.feature.accounts", + "ecommerce.feature.cart-checkout", + "ecommerce.feature.catalog-items", + "ecommerce.feature.catalog-discovery", + "ecommerce.feature.purchasing", + "ecommerce.feature.reviews", + "ecommerce.feature.warehouse-admin" + ], + "checks": [] + } + ] + }, + "stacks": [ + { + "id": "spacetime", + "adapterVersion": "1.4.0" + }, + { + "id": "postgres", + "adapterVersion": "1.6.0" + }, + { + "id": "mongodb", + "adapterVersion": "1.5.0" + } + ], + "agents": [ + { + "adapter": "reference-fixture", + "adapterVersion": "1.4.0", + "model": "reference-fixture" + } + ], + "conditions": [ + { + "id": "product-request", + "guidanceProfile": "neutral", + "repairPolicy": "scored-only", + "specifications": { + "levels": [ + { + "level": 1, + "requested": [], + "expected": [ + "ecommerce.spec.access-control", + "ecommerce.spec.concurrency-safety", + "ecommerce.spec.external-data-sync", + "ecommerce.spec.live-state", + "ecommerce.spec.state-durability", + "ecommerce.spec.transactional-integrity" + ], + "observed": [] + } + ] + } + } + ], + "repetitions": 1, + "parallelism": 1, + "ordering": { + "method": "balanced-rotation", + "seed": "replace-before-measurement" + }, + "budgets": { + "attemptTimeoutMinutes": 240, + "maxCostUsdPerAttempt": null + }, + "attemptPolicy": { + "retries": 1, + "retryOn": [ + "provider_failure" + ], + "excludeFromAnalysis": [ + "contaminated", + "harness_failure", + "inconclusive", + "ungraded" + ] + }, + "runtime": { + "releaseManifestSha256": null, + "controllerImage": null, + "buildImage": null, + "platform": "linux/amd64" + }, + "pricing": { + "currency": "USD", + "unit": "USD-per-million-tokens", + "capturedAt": "2026-08-12T00:00:00.000Z", + "source": "reference fixture adapter makes no billable provider calls", + "models": { + "reference-fixture": { + "input": 0, + "output": 0, + "cacheWrite5m": 0, + "cacheWrite1h": 0, + "cacheRead": 0 + } + } + }, + "analysis": { + "primaryMetric": "firstBuildScoreRate", + "secondaryMetrics": [ + "finalScoreRate", + "totalCostUsd", + "totalDurationMs", + "invalidAttemptRate" + ], + "dispersion": "median-iqr", + "invalidAttempts": "report-separately", + "missingData": "no-imputation", + "comparisonUnit": "stack-agent-condition-recipe" + } +} diff --git a/tools/stack-bench/appliance/campaign.paid-l1-l3.json b/tools/stack-bench/appliance/campaign.paid-l1-l3.json new file mode 100644 index 00000000000..bb06079b529 --- /dev/null +++ b/tools/stack-bench/appliance/campaign.paid-l1-l3.json @@ -0,0 +1,216 @@ +{ + "schemaVersion": 8, + "kind": "campaign-manifest", + "id": "paid-l1-l3-pilot", + "version": "1.0.0", + "state": "draft", + "title": "Three-stack L1-L3 progression pilot", + "track": "ecommerce", + "mode": { + "id": "sequential" + }, + "repair": { + "selection": "batch", + "budget": { + "total": 6 + } + }, + "levels": [ + 1, + 2, + 3 + ], + "selection": { + "levels": [ + { + "level": 1, + "recipe": "ecommerce.sequential-l1", + "features": [ + "ecommerce.feature.accounts", + "ecommerce.feature.cart-checkout", + "ecommerce.feature.catalog-items", + "ecommerce.feature.catalog-discovery", + "ecommerce.feature.purchasing", + "ecommerce.feature.reviews", + "ecommerce.feature.warehouse-admin" + ], + "checks": [] + }, + { + "level": 2, + "recipe": "ecommerce.sequential-l2", + "features": [ + "ecommerce.feature.accounts", + "ecommerce.feature.cart-checkout", + "ecommerce.feature.catalog-items", + "ecommerce.feature.catalog-discovery", + "ecommerce.feature.purchasing", + "ecommerce.feature.reviews", + "ecommerce.feature.warehouse-admin", + "ecommerce.inventory-operations-features", + "ecommerce.operations-access-features", + "ecommerce.returns-pricing-features" + ], + "checks": [] + }, + { + "level": 3, + "recipe": "ecommerce.sequential-l3", + "features": [ + "ecommerce.feature.accounts", + "ecommerce.feature.cart-checkout", + "ecommerce.feature.catalog-items", + "ecommerce.feature.catalog-discovery", + "ecommerce.feature.purchasing", + "ecommerce.feature.reviews", + "ecommerce.feature.warehouse-admin", + "ecommerce.inventory-operations-features", + "ecommerce.operations-access-features", + "ecommerce.returns-pricing-features", + "ecommerce.l3.reservations-features", + "ecommerce.l3.scheduled-restocks-features", + "ecommerce.l3.order-delivery-features", + "ecommerce.l3.cart-expiration-features" + ], + "checks": [] + } + ] + }, + "stacks": [ + { + "id": "spacetime", + "adapterVersion": "1.4.0" + }, + { + "id": "postgres", + "adapterVersion": "1.6.0" + }, + { + "id": "mongodb", + "adapterVersion": "1.5.0" + } + ], + "agents": [ + { + "adapter": "claude-code", + "adapterVersion": "1.17.2", + "model": "claude-sonnet-5" + } + ], + "conditions": [ + { + "id": "product-request", + "guidanceProfile": "neutral", + "repairPolicy": "scored-only", + "specifications": { + "levels": [ + { + "level": 1, + "requested": [], + "expected": [ + "ecommerce.spec.access-control", + "ecommerce.spec.concurrency-safety", + "ecommerce.spec.external-data-sync", + "ecommerce.spec.live-state", + "ecommerce.spec.state-durability", + "ecommerce.spec.transactional-integrity" + ], + "observed": [] + }, + { + "level": 2, + "requested": [], + "expected": [ + "ecommerce.inventory-operations-specifications", + "ecommerce.operations-access-specifications", + "ecommerce.returns-pricing-specifications", + "ecommerce.spec.access-control", + "ecommerce.spec.concurrency-safety", + "ecommerce.spec.external-data-sync", + "ecommerce.spec.live-state", + "ecommerce.spec.state-durability", + "ecommerce.spec.transactional-integrity" + ], + "observed": [] + }, + { + "level": 3, + "requested": [], + "expected": [ + "ecommerce.inventory-operations-specifications", + "ecommerce.l3.deferred-access-specifications", + "ecommerce.l3.deferred-durability-specifications", + "ecommerce.l3.deferred-integrity-specifications", + "ecommerce.l3.server-time-specifications", + "ecommerce.operations-access-specifications", + "ecommerce.returns-pricing-specifications", + "ecommerce.spec.access-control", + "ecommerce.spec.concurrency-safety", + "ecommerce.spec.external-data-sync", + "ecommerce.spec.live-state", + "ecommerce.spec.state-durability", + "ecommerce.spec.transactional-integrity" + ], + "observed": [] + } + ] + } + } + ], + "repetitions": 1, + "parallelism": 3, + "ordering": { + "method": "balanced-rotation", + "seed": "paid-l1-l3-pilot-v1" + }, + "budgets": { + "attemptTimeoutMinutes": 120, + "maxCostUsdPerAttempt": 30 + }, + "attemptPolicy": { + "retries": 0, + "retryOn": [], + "excludeFromAnalysis": [ + "contaminated", + "harness_failure", + "inconclusive", + "ungraded", + "provider_failure" + ] + }, + "runtime": { + "releaseManifestSha256": null, + "controllerImage": null, + "buildImage": null, + "platform": "linux/amd64" + }, + "pricing": { + "currency": "USD", + "unit": "USD-per-million-tokens", + "capturedAt": "2026-09-05T03:44:22.451Z", + "source": "https://platform.claude.com/docs/en/about-claude/pricing — verified current Sonnet 5 standard rates; subscription usage is normalized API-equivalent token cost, not an invoice charge", + "models": { + "claude-sonnet-5": { + "input": 2, + "output": 10, + "cacheWrite5m": 2.5, + "cacheWrite1h": 4, + "cacheRead": 0.2 + } + } + }, + "analysis": { + "primaryMetric": "checkCompletionRate", + "secondaryMetrics": [ + "totalCostUsd", + "totalTokens", + "firstBuildScoreRate", + "totalDurationMs", + "invalidAttemptRate" + ], + "dispersion": "median-iqr", + "invalidAttempts": "report-separately", + "missingData": "no-imputation", + "comparisonUnit": "stack-agent-condition-recipe" + } +} diff --git a/tools/stack-bench/appliance/campaign.paid-l1.json b/tools/stack-bench/appliance/campaign.paid-l1.json new file mode 100644 index 00000000000..c1afb4e8165 --- /dev/null +++ b/tools/stack-bench/appliance/campaign.paid-l1.json @@ -0,0 +1,140 @@ +{ + "schemaVersion": 8, + "kind": "campaign-manifest", + "id": "paid-l1-demo", + "version": "1.0.0", + "state": "draft", + "title": "Three-stack L1 demo", + "track": "ecommerce", + "mode": { + "id": "sequential" + }, + "repair": { + "selection": "batch", + "budget": { + "total": 0 + } + }, + "levels": [ + 1 + ], + "selection": { + "levels": [ + { + "level": 1, + "recipe": "ecommerce.sequential-l1", + "features": [ + "ecommerce.feature.accounts", + "ecommerce.feature.cart-checkout", + "ecommerce.feature.catalog-items", + "ecommerce.feature.catalog-discovery", + "ecommerce.feature.purchasing", + "ecommerce.feature.reviews", + "ecommerce.feature.warehouse-admin" + ], + "checks": [] + } + ] + }, + "stacks": [ + { + "id": "spacetime", + "adapterVersion": "1.4.0" + }, + { + "id": "postgres", + "adapterVersion": "1.6.0" + }, + { + "id": "mongodb", + "adapterVersion": "1.5.0" + } + ], + "agents": [ + { + "adapter": "claude-code", + "adapterVersion": "1.17.2", + "model": "claude-sonnet-5" + } + ], + "conditions": [ + { + "id": "product-request", + "guidanceProfile": "neutral", + "repairPolicy": "scored-only", + "specifications": { + "levels": [ + { + "level": 1, + "requested": [], + "expected": [ + "ecommerce.spec.access-control", + "ecommerce.spec.concurrency-safety", + "ecommerce.spec.external-data-sync", + "ecommerce.spec.live-state", + "ecommerce.spec.state-durability", + "ecommerce.spec.transactional-integrity" + ], + "observed": [] + } + ] + } + } + ], + "repetitions": 1, + "parallelism": 3, + "ordering": { + "method": "balanced-rotation", + "seed": "paid-l1-demo-v1" + }, + "budgets": { + "attemptTimeoutMinutes": 60, + "maxCostUsdPerAttempt": 10 + }, + "attemptPolicy": { + "retries": 0, + "retryOn": [], + "excludeFromAnalysis": [ + "contaminated", + "harness_failure", + "inconclusive", + "ungraded", + "provider_failure" + ] + }, + "runtime": { + "releaseManifestSha256": null, + "controllerImage": null, + "buildImage": null, + "platform": "linux/amd64" + }, + "pricing": { + "currency": "USD", + "unit": "USD-per-million-tokens", + "capturedAt": "2026-09-05T03:44:22.451Z", + "source": "https://platform.claude.com/docs/en/about-claude/pricing — verified current Sonnet 5 standard rates; subscription usage is normalized API-equivalent token cost, not an invoice charge", + "models": { + "claude-sonnet-5": { + "input": 2, + "output": 10, + "cacheWrite5m": 2.5, + "cacheWrite1h": 4, + "cacheRead": 0.2 + } + } + }, + "analysis": { + "primaryMetric": "checkCompletionRate", + "secondaryMetrics": [ + "totalCostUsd", + "totalTokens", + "firstBuildScoreRate", + "totalDurationMs", + "invalidAttemptRate" + ], + "dispersion": "median-iqr", + "invalidAttempts": "report-separately", + "missingData": "no-imputation", + "comparisonUnit": "stack-agent-condition-recipe" + } +} diff --git a/tools/stack-bench/appliance/campaign.product-brief-reference.json b/tools/stack-bench/appliance/campaign.product-brief-reference.json new file mode 100644 index 00000000000..a8133b1feaa --- /dev/null +++ b/tools/stack-bench/appliance/campaign.product-brief-reference.json @@ -0,0 +1,115 @@ +{ + "schemaVersion": 8, + "kind": "campaign-manifest", + "id": "ecommerce-l1-product-brief-reference", + "version": "2.0.0", + "state": "draft", + "title": "Ecommerce L1 product brief and quality validation", + "track": "ecommerce", + "mode": { "id": "sequential" }, + "repair": { "selection": "batch", "budget": { "total": 0 } }, + "levels": [1], + "selection": { + "levels": [ + { + "level": 1, + "recipe": "ecommerce.sequential-l1", + "features": [ + "ecommerce.feature.accounts", + "ecommerce.feature.cart-checkout", + "ecommerce.feature.catalog-items", + "ecommerce.feature.catalog-discovery", + "ecommerce.feature.purchasing", + "ecommerce.feature.reviews", + "ecommerce.feature.warehouse-admin" + ], + "checks": [] + } + ] + }, + "stacks": [ + { "id": "spacetime", "adapterVersion": "1.4.0" }, + { "id": "postgres", "adapterVersion": "1.6.0" }, + { "id": "mongodb", "adapterVersion": "1.5.0" } + ], + "agents": [ + { + "adapter": "reference-fixture", + "adapterVersion": "1.4.0", + "model": "reference-fixture" + } + ], + "conditions": [ + { + "id": "product-brief-quality", + "guidanceProfile": "neutral", + "repairPolicy": "scored-only", + "specifications": { + "levels": [ + { + "level": 1, + "requested": [], + "expected": [ + "ecommerce.spec.access-control", + "ecommerce.spec.concurrency-safety", + "ecommerce.spec.external-data-sync", + "ecommerce.spec.live-state", + "ecommerce.spec.state-durability", + "ecommerce.spec.transactional-integrity" + ], + "observed": [] + } + ] + } + } + ], + "repetitions": 2, + "parallelism": 1, + "ordering": { + "method": "balanced-rotation", + "seed": "product-brief-quality-reference-1" + }, + "budgets": { + "attemptTimeoutMinutes": 60, + "maxCostUsdPerAttempt": null + }, + "attemptPolicy": { + "retries": 1, + "retryOn": ["harness_failure", "inconclusive"], + "excludeFromAnalysis": ["contaminated", "harness_failure", "inconclusive", "ungraded"] + }, + "runtime": { + "releaseManifestSha256": null, + "controllerImage": null, + "buildImage": null, + "platform": "linux/amd64" + }, + "pricing": { + "currency": "USD", + "unit": "USD-per-million-tokens", + "capturedAt": "2026-08-16T00:00:00.000Z", + "source": "reference fixture adapter makes no billable provider calls", + "models": { + "reference-fixture": { + "input": 0, + "output": 0, + "cacheWrite5m": 0, + "cacheWrite1h": 0, + "cacheRead": 0 + } + } + }, + "analysis": { + "primaryMetric": "firstBuildScoreRate", + "secondaryMetrics": [ + "finalScoreRate", + "totalCostUsd", + "totalDurationMs", + "invalidAttemptRate" + ], + "dispersion": "median-iqr", + "invalidAttempts": "report-separately", + "missingData": "no-imputation", + "comparisonUnit": "stack-agent-condition-recipe" + } +} diff --git a/tools/stack-bench/appliance/controller.ts b/tools/stack-bench/appliance/controller.ts new file mode 100644 index 00000000000..8a5d9ab985d --- /dev/null +++ b/tools/stack-bench/appliance/controller.ts @@ -0,0 +1,242 @@ +#!/usr/bin/env node + +import { spawn } from 'node:child_process'; +import { randomUUID } from 'node:crypto'; +import { join } from 'node:path'; +import { pathToFileURL } from 'node:url'; + +import { STACK_BENCH_ROOT } from '../src/package-root.js'; +import { resolveContainerImage } from '../src/runtime/container-image.js'; +import { parsePreflightArgs } from '../commands/preflight-cli.js'; +import { parseBenchArguments } from '../commands/bench-arguments.js'; +import { AGENT_ADAPTER_REGISTRY } from '../src/agents/agent-adapters.js'; +import { stateVolumeCommand } from './state-volume.js'; + +const RUNTIME_ROOT = join(STACK_BENCH_ROOT, 'dist'); + +const COMMANDS = Object.freeze({ + 'demo': [join(RUNTIME_ROOT, 'appliance', 'demo.js')], + 'init-deps': [join(RUNTIME_ROOT, 'appliance', 'dependency-volume.js'), 'init'], + 'verify-deps': [join(RUNTIME_ROOT, 'appliance', 'dependency-volume.js'), 'verify'], + 'preflight': [join(RUNTIME_ROOT, 'commands', 'preflight.js')], + 'qualify-reference': [join(RUNTIME_ROOT, 'src', 'references', 'reference-live.js')], + 'qualify-null': [join(RUNTIME_ROOT, 'commands', 'null-control.js')], + 'qualification': [join(RUNTIME_ROOT, 'commands', 'qualification-cli.js')], + 'pack-budget': [join(RUNTIME_ROOT, 'commands', 'pack-budget.js')], + 'job': [join(RUNTIME_ROOT, 'commands', 'job-cli.js')], + 'campaign': [join(RUNTIME_ROOT, 'commands', 'campaign-cli.js')], + 'dashboard': [join(RUNTIME_ROOT, 'dashboard', 'dashboard-server.js')], + 'repair': [join(RUNTIME_ROOT, 'commands', 'repair-cli.js')], + 'run': [join(RUNTIME_ROOT, 'commands', 'bench.js')], + 'verify-release': [join(RUNTIME_ROOT, 'src', 'releases', 'release-manifest.js'), 'verify'], + 'recover': [join(RUNTIME_ROOT, 'commands', 'recovery.js'), 'recover'], + 'recover-lease': [join(RUNTIME_ROOT, 'commands', 'recovery.js'), 'recover-lease'], +} satisfies Record); + +const COMMANDS_REQUIRING_AGENT_AUTH = new Set(['preflight', 'run']); + +export function controllerCommandRequiresAgentAuth(command: string | undefined, + args: string[] = []): boolean { + if (command === 'job' && ['prepare', 'start', 'work', 'worker'].includes(args[0] ?? '')) return true; + if (command === 'run' && args.some(value => value === '--grade-from' || value.startsWith('--grade-from='))) { + return !parseBenchArguments([process.execPath, 'bench', ...args]).gradeFrom; + } + if (command === 'preflight' && args.length) { + const request = parsePreflightArgs([process.execPath, 'preflight', ...args]); + return AGENT_ADAPTER_REGISTRY.get(request.agentAdapter).costLimit !== 'non-billable'; + } + if (command && COMMANDS_REQUIRING_AGENT_AUTH.has(command)) return true; + return command === 'campaign' && ['run', 'resume', 'extend'].includes(args[0] ?? ''); +} + +export function controllerRuntimeEnvironment(source: NodeJS.ProcessEnv = process.env, + resolveImage = resolveContainerImage): NodeJS.ProcessEnv { + if (!source.STACK_BENCH_CONTROLLER_IMAGE) { + throw new Error('STACK_BENCH_CONTROLLER_IMAGE is required for runtime work'); + } + return { ...source, STACK_BENCH_CONTROLLER_IMAGE_ID: + resolveImage(source.STACK_BENCH_CONTROLLER_IMAGE).id }; +} + +export function controllerRuntimeCommand(args: string[], source: NodeJS.ProcessEnv = process.env) { + if (!source.STACK_BENCH_COMPOSE_FILE || !source.STACK_BENCH_STATE_ROOT + || !source.STACK_BENCH_CONTROLLER_IMAGE || !(source.STACK_BENCH_BUILD_IMAGE ?? source.STACK_BENCH_IMAGE)) { + throw new Error('controller launch requires the setup environment and appliance Compose file'); + } + const ownership = randomUUID(); + const containerName = `stack-bench-controller-${ownership}`; + const ownershipLabel = `io.spacetimedb.stack-bench.controller-owner=${ownership}`; + const env: NodeJS.ProcessEnv = { ...controllerChildEnvironment(source, { requireAgentAuth: false }), + STACK_BENCH_BUILD_IMAGE: source.STACK_BENCH_BUILD_IMAGE ?? source.STACK_BENCH_IMAGE }; + return { executable: 'docker', containerName, ownershipLabel, + args: ['compose', '-f', source.STACK_BENCH_COMPOSE_FILE, 'run', '--rm', '--no-deps', + '--name', containerName, '--label', ownershipLabel, 'controller', ...args], + env }; +} + +export interface ResolvedControllerCommand { + executable: string; + args: string[]; +} + +export function resolveControllerCommand(argv: string[]): ResolvedControllerCommand | null { + const [command, ...rest] = argv; + if (!command || command === '--help' || command === 'help') return null; + if (!Object.hasOwn(COMMANDS, command)) { + throw new Error(`unknown controller command ${JSON.stringify(command)}`); + } + return { executable: process.execPath, + args: [...COMMANDS[command as keyof typeof COMMANDS], ...rest] }; +} + +export function controllerChildEnvironment(source: NodeJS.ProcessEnv = process.env, + { requireAgentAuth = true }: { requireAgentAuth?: boolean } = {}): NodeJS.ProcessEnv { + const env = { ...source }; + const modes: Record = { + 'subscription-token': ['STACK_BENCH_CLAUDE_OAUTH_TOKEN_FILE', 'CLAUDE_CODE_OAUTH_TOKEN_FILE'], + 'api-key': ['STACK_BENCH_ANTHROPIC_API_KEY_FILE', 'ANTHROPIC_API_KEY_FILE'], + 'openrouter-api-key': ['STACK_BENCH_OPENROUTER_API_KEY_FILE', 'OPENROUTER_API_KEY_FILE'], + 'openai-api-key': ['STACK_BENCH_OPENAI_API_KEY_FILE', 'OPENAI_API_KEY_FILE'], + 'openai-account': ['STACK_BENCH_CODEX_AUTH_FILE', 'CODEX_AUTH_FILE'], + }; + // Named jobs select per attempt. Keep the legacy default available without + // clearing credentials belonging to other providers. + if (source.STACK_BENCH_CREDENTIAL_PROFILES_FILE) { + const selected = modes[source.STACK_BENCH_AGENT_AUTH ?? 'subscription-token']; + if (selected && source[selected[0]]?.trim()) env[selected[1]] = source[selected[0]]!.trim(); + return env; + } + for (const [, variable] of Object.values(modes)) { + delete env[variable]; + delete env[variable.replace(/_FILE$/, '')]; + } + delete env.STACK_BENCH_AGENT_API_KEY; + if (!requireAgentAuth) return env; + const mode = source.STACK_BENCH_AGENT_AUTH ?? 'subscription-token'; + const selected = Object.hasOwn(modes, mode) ? modes[mode] : undefined; + if (!selected) throw new Error(`STACK_BENCH_AGENT_AUTH must be ${Object.keys(modes).join(' or ')}`); + const [sourceName, variable] = selected; + const path = source[sourceName]?.trim(); + if (!path) throw new Error(`${mode} auth requires ${sourceName}`); + env[variable] = path; + return env; +} + +interface SignalChild { + kill(signal: NodeJS.Signals): unknown; +} + +interface SignalSource { + on(signal: NodeJS.Signals, listener: () => void): unknown; + off(signal: NodeJS.Signals, listener: () => void): unknown; +} + +export function forwardControllerSignals(child: SignalChild, + source: SignalSource = process): () => void { + const signals: NodeJS.Signals[] = ['SIGINT', 'SIGTERM']; + const listeners = new Map void>(signals.map(signal => + [signal, () => { child.kill(signal); }])); + for (const [signal, listener] of listeners) source.on(signal, listener); + return () => { + for (const [signal, listener] of listeners) source.off(signal, listener); + }; +} + +function help(): void { + process.stdout.write('Stack Bench controller\n' + + '\n' + + 'Docker setup\n' + + ' setup prepare the state volume and print operator.env\n' + + ' set-secret read one secret from stdin into the volume mounted at /state\n' + + '\n' + + 'A campaign compares stacks by building the same product on each. Point\n' + + 'commands at the durable plans/ and campaigns/ directories.\n' + + '\n' + + 'Run a campaign\n' + + ' job options list workload and agent choices\n' + + ' job prepare review selections without running models\n' + + ' job start --host start a reviewed run\n' + + ' job submit submit an idempotent execution job\n' + + ' job work --host claim and execute one submitted job\n' + + ' job worker --host --concurrency dispatch queued jobs automatically\n' + + ' job list|status |cancel inspect or cancel submitted work\n' + + ' preflight --backend --track --levels \n' + + ' verify the runner without creating an attempt\n' + + ' campaign validate compile a plan file and report what is wrong with it\n' + + ' campaign show print the compiled plan\n' + + ' campaign trial --out run the plan with a model-free agent\n' + + ' campaign run --out run the plan; run it again on the same to continue\n' + + ' campaign resume --out continue an interrupted dependency attempt from its saved state\n' + + ' campaign extend --from --depth --out continue a finished campaign deeper\n' + + ' campaign stop stop owned active work and retain its evidence\n' + + ' campaign pause-status inspect a planned between-depth hold\n' + + ' campaign continue-depth release the cohort at its planned depth boundary\n' + + ' campaign status [--full] what the campaign is doing now, from its saved state\n' + + ' campaign inspect every attempt, level, and check with its evidence\n' + + ' campaign report write the JSON and HTML report\n' + + ' campaign audit check a finished reference campaign against its promises\n' + + ' campaign grant-repairs --attempt --level --repairs add repair budget\n' + + ' campaign grant-time --attempt --grant-id --minutes add time\n' + + ' campaign reconcile --out clean up after an interruption and prove it\n' + + ' campaign modes list the campaign modes this controller knows\n' + + ' dashboard [--port N] serve the local dashboard\n' + + '\n' + + 'One attempt outside a campaign\n' + + ' run --backend --track --levels --out [...] build and grade one attempt\n' + + ' run --grade-from --grade-level --check --out replay saved dependency source without model calls\n' + + ' repair status --level can a failed level continue?\n' + + ' repair grant --level --repairs add one repair budget\n' + + '\n' + + 'Qualify the grader\n' + + ' qualify-reference --track --level grade the hand-built reference app, or its mutations\n' + + ' --mutation-workers N split the mutation run across 1 to 8 isolated workers\n' + + ' qualify-null --track --level prove an empty app scores nothing\n' + + ' qualification status --track --level which grading evidence is still missing\n' + + ' pack-budget recommend --track --level --recipe --evidence derive pack limits from reference evidence\n' + + '\n' + + 'Recover and verify\n' + + ' recover retry cleanup for an interrupted attempt, or keep its quarantine\n' + + ' recover-lease --out recover when the attempt state was not kept\n' + + ' verify-release verify a candidate or signed release\n' + + ' init-deps | verify-deps create or verify the release dependency volume\n'); +} + +interface ChildOutcome { + code: number | null; + signal: NodeJS.Signals | null; +} + +async function main(argv: string[]): Promise { + const command = argv[2]; + if (command === 'setup' || command === 'set-secret') { + stateVolumeCommand(command, argv.slice(3)); + return; + } + const resolved = resolveControllerCommand(argv.slice(2)); + if (!resolved) { help(); return; } + let env = controllerChildEnvironment(process.env, + { requireAgentAuth: controllerCommandRequiresAgentAuth(command, argv.slice(3)) }); + const runtime = ['preflight', 'run', 'qualify-reference', 'qualify-null', 'recover', 'recover-lease'] + .includes(command ?? '') || (command === 'campaign' + && ['run', 'trial', 'resume', 'extend', 'reconcile'].includes(argv[3] ?? '')) + || (command === 'job' && ['start', 'work', 'worker'].includes(argv[3] ?? '')); + if (runtime) env = controllerRuntimeEnvironment(env); + const child = spawn(resolved.executable, resolved.args, { stdio: 'inherit', env }); + const stopForwardingSignals = forwardControllerSignals(child); + let outcome: ChildOutcome; + try { + outcome = await new Promise((resolveExit, reject) => { + child.once('error', reject); + child.once('exit', (code, signal) => { resolveExit({ code, signal }); }); + }); + } finally { stopForwardingSignals(); } + if (outcome.signal) process.kill(process.pid, outcome.signal); + process.exitCode = outcome.code ?? 1; +} + +if (import.meta.url === pathToFileURL(process.argv[1] ?? '').href) { + main(process.argv).catch((error: unknown) => { + console.error(`stack-bench-controller: ${error instanceof Error ? error.message : String(error)}`); + process.exitCode = 2; + }); +} diff --git a/tools/stack-bench/appliance/demo.compose.yaml b/tools/stack-bench/appliance/demo.compose.yaml new file mode 100644 index 00000000000..06267966444 --- /dev/null +++ b/tools/stack-bench/appliance/demo.compose.yaml @@ -0,0 +1,28 @@ +name: stack-bench-demo + +services: + build-image: + image: stack-bench-build:local + platform: linux/amd64 + build: + context: ../container + dockerfile: Dockerfile + entrypoint: ["/bin/true"] + demo: + image: stack-bench-controller:local + platform: linux/amd64 + build: + context: ../../.. + dockerfile: tools/stack-bench/appliance/Controller.Dockerfile + depends_on: + build-image: + condition: service_completed_successfully + init: true + command: ["demo"] + volumes: + - /var/run/docker.sock:/var/run/docker.sock + - state:/state + +volumes: + state: + name: stack-bench-state diff --git a/tools/stack-bench/appliance/demo.ts b/tools/stack-bench/appliance/demo.ts new file mode 100644 index 00000000000..8ff0902403b --- /dev/null +++ b/tools/stack-bench/appliance/demo.ts @@ -0,0 +1,66 @@ +import { spawn } from 'node:child_process'; +import { chmodSync, existsSync, writeFileSync } from 'node:fs'; +import { join } from 'node:path'; +import { pathToFileURL } from 'node:url'; +import { STACK_BENCH_ROOT } from '../src/package-root.js'; +import { readCampaignState } from '../src/campaigns/campaign-scheduler.js'; +import { forwardControllerSignals } from './controller.js'; +import { prepareStateVolume } from './state-volume.js'; + +export function demoConfiguration(setup: string, source: NodeJS.ProcessEnv = process.env) { + const prepared: NodeJS.ProcessEnv = {}; + for (const line of setup.split('\n').filter(Boolean)) { + const separator = line.indexOf('='); + if (separator < 1) throw new Error('Invalid setup environment'); + prepared[line.slice(0, separator)] = line.slice(separator + 1); + } + const digest = prepared.STACK_BENCH_CONTROLLER_IMAGE?.match(/^(?:.*@)?sha256:([a-f0-9]{64})$/)?.[1]; + if (!digest) throw new Error('Demo requires a resolved controller image digest'); + prepared.STACK_BENCH_RELEASE_DEPS_VOLUME = `stack-bench-release-deps-${digest.slice(0, 12)}`; + const output = `campaigns/demo-${digest.slice(0, 12)}`; + const compose = ['compose', '-f', join(STACK_BENCH_ROOT, 'appliance/docker-compose.yaml')]; + return { env: { ...source, ...prepared }, output, + dashboard: [...compose, '--profile', 'dashboard', 'up', '-d', 'dashboard'], + campaign: [...compose, 'run', '--rm', '-T', '--name', `stack-bench-demo-${digest.slice(0, 12)}`, + 'controller', 'campaign', 'trial', 'plans/demo.json', '--out', output], + savedEnvironment: Object.entries(prepared) + .map(([key, value]) => `${key}=${value ?? ''}`).join('\n') + '\n', + }; +} + +async function docker(args: string[], env: NodeJS.ProcessEnv): Promise { + const child = spawn('docker', args, { env, stdio: 'inherit' }); + const stopForwarding = forwardControllerSignals(child); + try { + await new Promise((resolve, reject) => { + child.once('error', reject); + child.once('exit', (code, signal) => code === 0 ? resolve() + : reject(new Error(`Demo Docker command failed (${signal ?? code})`))); + }); + } finally { stopForwarding(); } +} + +export async function demoCommand(args: string[]): Promise { + if (args.length) throw new Error('demo accepts no arguments; set image references through the environment'); + const config = demoConfiguration(prepareStateVolume()); + const environmentPath = '/state/controller-home/demo.env'; + writeFileSync(environmentPath, config.savedEnvironment, { mode: 0o600 }); + chmodSync(environmentPath, 0o600); + await docker(config.dashboard, config.env); + console.log('Stack Bench dashboard: http://127.0.0.1:7331'); + const directory = join('/state/results', config.output); + if (existsSync(join(directory, 'state.json'))) { + const { state } = readCampaignState(directory); + console.log(`Existing demo campaign: ${state.status} (${config.output})`); + if (state.status !== 'completed') throw new Error(`Existing demo needs attention: ${state.status}`); + return; + } + await docker(config.campaign, config.env); +} + +if (process.argv[1] && pathToFileURL(process.argv[1]).href === import.meta.url) { + demoCommand(process.argv.slice(2)).catch((error: unknown) => { + console.error(error instanceof Error ? error.message : String(error)); + process.exitCode = 1; + }); +} diff --git a/tools/stack-bench/appliance/dependency-volume.ts b/tools/stack-bench/appliance/dependency-volume.ts new file mode 100644 index 00000000000..e6f49e55a86 --- /dev/null +++ b/tools/stack-bench/appliance/dependency-volume.ts @@ -0,0 +1,165 @@ +#!/usr/bin/env node + +import { createHash } from 'node:crypto'; +import { + chmodSync, copyFileSync, existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, + renameSync, rmSync, writeFileSync, +} from 'node:fs'; +import { dirname, join, relative, resolve, sep } from 'node:path'; +import { pathToFileURL } from 'node:url'; +import { parseArgs } from 'node:util'; + +const MARKER = '.stack-bench-release-deps.json'; + +export interface DependencyManifestFile { + path: string; + size: number; + mode: number; + sha256: string; +} + +export interface DependencyManifest { + schemaVersion: 1; + files: DependencyManifestFile[]; +} + +interface DependencyVerification { + manifestSha256: string; + files: number; +} + +interface DependencyInitialization extends DependencyVerification { + initialized: boolean; +} + +function sha256Bytes(bytes: string | NodeJS.ArrayBufferView): string { + return createHash('sha256').update(bytes).digest('hex'); +} + +function normalizedRelative(root: string, path: string): string { + const value = relative(root, path).split(sep).join('/'); + if (!value || value.startsWith('../') || value === '..') throw new Error(`path escapes dependency root: ${path}`); + return value; +} + +function walk(root: string, current = root): string[] { + const files: string[] = []; + for (const entry of readdirSync(current, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) { + const path = join(current, entry.name); + if (entry.isSymbolicLink()) throw new Error(`dependency tree cannot contain symlinks: ${normalizedRelative(root, path)}`); + if (entry.isDirectory()) files.push(...walk(root, path)); + else if (entry.isFile()) files.push(path); + else throw new Error(`dependency tree contains unsupported entry: ${normalizedRelative(root, path)}`); + } + return files; +} + +export function createDependencyManifest(root: string): DependencyManifest { + const absolute = resolve(root); + if (!existsSync(absolute) || !lstatSync(absolute).isDirectory()) { + throw new Error(`dependency source is not a directory: ${absolute}`); + } + const files = walk(absolute).map(path => { + const bytes = readFileSync(path); + return { path: normalizedRelative(absolute, path), size: bytes.length, + mode: lstatSync(path).mode & 0o777, sha256: sha256Bytes(bytes) }; + }); + if (!files.length) throw new Error('dependency source is empty'); + return { schemaVersion: 1, files }; +} + +export function manifestSha256(manifest: DependencyManifest): string { + return sha256Bytes(`${JSON.stringify(manifest)}\n`); +} + +export function verifyDependencyTree(root: string, manifest: DependencyManifest, + { allowMarker = false }: { allowMarker?: boolean } = {}): DependencyVerification { + if (!manifest || manifest.schemaVersion !== 1 || !Array.isArray(manifest.files) || !manifest.files.length) { + throw new Error('dependency manifest is invalid'); + } + const absolute = resolve(root); + const actual = createDependencyManifest(absolute); + if (allowMarker) actual.files = actual.files.filter(file => file.path !== MARKER); + if (JSON.stringify(actual.files) !== JSON.stringify(manifest.files)) { + throw new Error(`dependency tree does not match manifest ${manifestSha256(manifest)}`); + } + return { manifestSha256: manifestSha256(manifest), files: manifest.files.length }; +} + +export function initializeDependencyVolume({ source, target, manifest }: + { source: string; target: string; manifest: DependencyManifest }): DependencyInitialization { + const sourceRoot = resolve(source); + const targetRoot = resolve(target); + const verified = verifyDependencyTree(sourceRoot, manifest); + mkdirSync(targetRoot, { recursive: true, mode: 0o755 }); + const markerPath = join(targetRoot, MARKER); + const existing = readdirSync(targetRoot); + if (existing.length) { + if (!existsSync(markerPath)) throw new Error('dependency volume is non-empty but has no release marker'); + const marker = JSON.parse(readFileSync(markerPath, 'utf8')); + if (marker.schemaVersion !== 1 || marker.manifestSha256 !== verified.manifestSha256) { + throw new Error('dependency volume belongs to a different release'); + } + verifyDependencyTree(targetRoot, manifest, { allowMarker: true }); + return { ...verified, initialized: false }; + } + + const staging = join(targetRoot, `.staging-${process.pid}`); + mkdirSync(staging, { mode: 0o700 }); + try { + for (const file of manifest.files) { + const from = join(sourceRoot, ...file.path.split('/')); + const to = join(staging, ...file.path.split('/')); + mkdirSync(dirname(to), { recursive: true }); + copyFileSync(from, to); + chmodSync(to, file.mode); + } + for (const entry of readdirSync(staging)) renameSync(join(staging, entry), join(targetRoot, entry)); + rmSync(staging, { recursive: true, force: true }); + writeFileSync(markerPath, `${JSON.stringify({ schemaVersion: 1, + manifestSha256: verified.manifestSha256 })}\n`, { flag: 'wx', mode: 0o444 }); + verifyDependencyTree(targetRoot, manifest, { allowMarker: true }); + return { ...verified, initialized: true }; + } catch (error) { + rmSync(staging, { recursive: true, force: true }); + throw error; + } +} + +function main(argv: string[]): void { + const { values, positionals } = parseArgs({ args: argv.slice(2), allowPositionals: true, + options: { + source: { type: 'string', default: '/opt/stack-bench-embedded-deps' }, + target: { type: 'string', default: '/opt/stack-bench-release-deps' }, + manifest: { type: 'string', default: '/opt/stack-bench/dependency-manifest.json' }, + out: { type: 'string' }, + } }); + const [command] = positionals; + const source = values.source; + const target = values.target; + const manifestPath = values.manifest; + if (command === 'manifest') { + const output = values.out; + if (!output) throw new Error('manifest requires --out'); + writeFileSync(resolve(output), `${JSON.stringify(createDependencyManifest(source), null, 2)}\n`, { flag: 'wx' }); + return; + } + const manifest: DependencyManifest = JSON.parse(readFileSync(resolve(manifestPath), 'utf8')); + if (command === 'init') { + process.stdout.write(`${JSON.stringify(initializeDependencyVolume({ source, target, manifest }))}\n`); + return; + } + if (command === 'verify') { + process.stdout.write(`${JSON.stringify(verifyDependencyTree(target, manifest, { allowMarker: true }))}\n`); + return; + } + throw new Error('usage: dependency-volume manifest|init|verify [options]'); +} + +if (import.meta.url === pathToFileURL(process.argv[1] ?? '').href) { + try { main(process.argv); } + catch (error) { + console.error(`dependency-volume: ${error instanceof Error ? error.message : String(error)}`); + process.exit(2); + } +} diff --git a/tools/stack-bench/appliance/docker-compose.yaml b/tools/stack-bench/appliance/docker-compose.yaml new file mode 100644 index 00000000000..e32295e82fe --- /dev/null +++ b/tools/stack-bench/appliance/docker-compose.yaml @@ -0,0 +1,164 @@ +name: stack-bench-appliance + +services: + deps-init: + image: ${STACK_BENCH_CONTROLLER_IMAGE:?set STACK_BENCH_CONTROLLER_IMAGE to the manifest digest reference} + platform: linux/amd64 + command: ["init-deps"] + read_only: true + cap_drop: ["ALL"] + security_opt: ["no-new-privileges:true"] + volumes: + - type: volume + source: release-deps + target: /opt/stack-bench-release-deps + tmpfs: + - /tmp:size=64m,mode=1777 + + controller: + image: ${STACK_BENCH_CONTROLLER_IMAGE:?set STACK_BENCH_CONTROLLER_IMAGE to the manifest digest reference} + platform: linux/amd64 + init: true + network_mode: host + working_dir: ${STACK_BENCH_STATE_ROOT:?run controller setup}/results + read_only: true + cap_drop: ["ALL"] + security_opt: ["no-new-privileges:true"] + depends_on: + deps-init: + condition: service_completed_successfully + npm-cache: + condition: service_healthy + environment: + STACK_BENCH_CONTROLLER_IMAGE: ${STACK_BENCH_CONTROLLER_IMAGE:?set STACK_BENCH_CONTROLLER_IMAGE to the manifest digest reference} + STACK_BENCH_BUILD_IMAGE: ${STACK_BENCH_BUILD_IMAGE:?set STACK_BENCH_BUILD_IMAGE} + STACK_BENCH_STATE_ROOT: ${STACK_BENCH_STATE_ROOT:?run controller setup} + STACK_BENCH_NPM_REGISTRY: http://127.0.0.1:4873/ + STACK_BENCH_IMAGE: ${STACK_BENCH_BUILD_IMAGE:?set STACK_BENCH_BUILD_IMAGE to the manifest digest reference} + STACK_BENCH_RELEASE_MANIFEST: ${STACK_BENCH_RELEASE_MANIFEST:-} + STACK_BENCH_APPLIANCE: "1" + STACK_BENCH_RUNNER_CAPACITY: ${STACK_BENCH_RUNNER_CAPACITY:-} + STACK_BENCH_COMPOSE_FILE: /opt/stack-bench/appliance/docker-compose.yaml + STACK_BENCH_WORK_DIR: ${STACK_BENCH_STATE_ROOT:?run controller setup}/work + STACK_BENCH_RESULTS_DIR: ${STACK_BENCH_STATE_ROOT:?run controller setup}/results + STACK_BENCH_SUPERVISOR_DIR: ${STACK_BENCH_STATE_ROOT:?run controller setup}/controller-home/supervisor + STACK_BENCH_RUNTIME_DIR: ${STACK_BENCH_STATE_ROOT:?run controller setup}/controller-home/runtime + STACK_BENCH_RESOURCE_LOCK_DIR: ${STACK_BENCH_STATE_ROOT:?run controller setup}/controller-home/resource-locks + STACK_BENCH_RELEASE_DEPS_VOLUME: ${STACK_BENCH_RELEASE_DEPS_VOLUME:-stack-bench-release-deps} + STACK_BENCH_LINUX_CLI: /opt/stack-bench-release-deps/spacetimedb-cli + STDB_PACKAGE: /opt/stack-bench-release-deps/bindings-typescript + SPACETIME_BIN: /opt/stack-bench-release-deps/spacetimedb-cli + STACK_BENCH_CREDENTIAL_PROFILES_FILE: ${STACK_BENCH_CREDENTIAL_PROFILES_FILE:-} + STACK_BENCH_AGENT_AUTH: ${STACK_BENCH_AGENT_AUTH:-subscription-token} + STACK_BENCH_CLAUDE_OAUTH_TOKEN_FILE: ${STACK_BENCH_CLAUDE_OAUTH_TOKEN_FILE:-${STACK_BENCH_STATE_ROOT:?run controller setup}/secrets/claude_subscription_token} + STACK_BENCH_ANTHROPIC_API_KEY_FILE: ${STACK_BENCH_ANTHROPIC_API_KEY_FILE:-} + STACK_BENCH_OPENROUTER_API_KEY_FILE: ${STACK_BENCH_OPENROUTER_API_KEY_FILE:-} + STACK_BENCH_OPENAI_API_KEY_FILE: ${STACK_BENCH_OPENAI_API_KEY_FILE:-} + STACK_BENCH_CODEX_AUTH_FILE: ${STACK_BENCH_CODEX_AUTH_FILE:-} + HOME: ${STACK_BENCH_STATE_ROOT:?run controller setup}/controller-home + volumes: + - type: bind + source: /var/run/docker.sock + target: /var/run/docker.sock + - type: volume + source: state + target: ${STACK_BENCH_STATE_ROOT:?run controller setup} + - type: volume + source: release-deps + target: /opt/stack-bench-release-deps + read_only: true + tmpfs: + - /tmp:size=1g,mode=1777 + command: ["--help"] + logging: &bounded-logs + driver: json-file + options: + max-size: "10m" + max-file: "3" + + worker: + restart: on-failure:3 + extends: + service: controller + profiles: ["worker"] + # SIGTERM stops admission and drains claimed campaigns. Explicit job cancellation stops a run. + stop_grace_period: 24h + command: ["job", "worker", "--host", "${STACK_BENCH_HOST_ID:-}", "--concurrency", "${STACK_BENCH_JOB_CONCURRENCY:-}"] + + dashboard: + extends: + service: controller + profiles: ["dashboard"] + network_mode: bridge + ports: + - "127.0.0.1:7331:7331" + command: ["dashboard", "--host", "0.0.0.0", "--port", "7331", "--allow-container-bind"] + # Pull-through npm registry cache. Coding containers install through it, so a + # package reaches the public registry once per appliance, not once per run. + npm-cache: + image: verdaccio/verdaccio:6@sha256:09b403888c8f73ba9336d7fb3464622f64ea905a64bc46a87c847387c536d4dd + platform: linux/amd64 + container_name: stack-bench-npm-cache + cpus: 1 + mem_limit: 2g + pids_limit: 128 + logging: *bounded-logs + cap_drop: ["ALL"] + security_opt: ["no-new-privileges:true"] + ports: ["127.0.0.1:4873:4873"] + configs: + - source: npm-cache-config + target: /verdaccio/conf/config.yaml + volumes: + - npmcache:/verdaccio/storage + healthcheck: + test: ["CMD", "wget", "-qO-", "http://127.0.0.1:4873/-/ping"] + interval: 5s + timeout: 5s + retries: 12 + +configs: + npm-cache-config: + content: | + storage: /verdaccio/storage/data + plugins: /verdaccio/plugins + web: + enable: false + auth: + htpasswd: + file: /verdaccio/storage/htpasswd + max_users: -1 + uplinks: + npmjs: + url: https://registry.npmjs.org/ + cache: true + timeout: 60s + maxage: 10m + max_fails: 4 + fail_timeout: 2m + packages: + '@*/*': + access: $$all + publish: nobody + unpublish: nobody + proxy: npmjs + '**': + access: $$all + publish: nobody + unpublish: nobody + proxy: npmjs + server: + keepAliveTimeout: 60 + log: + type: stdout + format: pretty + level: warn + +volumes: + release-deps: + name: ${STACK_BENCH_RELEASE_DEPS_VOLUME:-stack-bench-release-deps} + state: + external: true + name: stack-bench-state + npmcache: + name: stack-bench-appliance-npmcache diff --git a/tools/stack-bench/appliance/operator.env.example b/tools/stack-bench/appliance/operator.env.example new file mode 100644 index 00000000000..4bd5966b265 --- /dev/null +++ b/tools/stack-bench/appliance/operator.env.example @@ -0,0 +1,33 @@ +# Prefer the controller setup command. It prints this file with the Docker +# volume mountpoint and immutable local image IDs already resolved. +STACK_BENCH_STATE_ROOT=/var/lib/docker/volumes/stack-bench-state/_data + +# Subscription billing is the default. Generate a dedicated long-lived Claude +# setup token, write only the token to this mode-0600 file, and never commit it. +STACK_BENCH_AGENT_AUTH=subscription-token +STACK_BENCH_CLAUDE_OAUTH_TOKEN_FILE=${STACK_BENCH_STATE_ROOT}/secrets/claude_subscription_token + +# To bill through an API key instead, set the mode to api-key and provide an +# absolute path below STACK_BENCH_STATE_ROOT containing only that key. +# STACK_BENCH_ANTHROPIC_API_KEY_FILE=${STACK_BENCH_STATE_ROOT}/secrets/anthropic_api_key + +# For a codex agent, select openai-api-key or openai-account explicitly. +# Account mode uses an unexpired Codex login access token, with no automatic refresh. +# STACK_BENCH_AGENT_AUTH=openai-api-key +# STACK_BENCH_OPENAI_API_KEY_FILE=${STACK_BENCH_STATE_ROOT}/secrets/openai_api_key +# STACK_BENCH_AGENT_AUTH=openai-account +# STACK_BENCH_CODEX_AUTH_FILE=${STACK_BENCH_STATE_ROOT}/secrets/codex_auth + +# For the openrouter adapter, store the key with set-secret openrouter_api_key. +# Freeze model, providerRoute, and maxOutputTokens in each campaign agent selection. +# STACK_BENCH_AGENT_AUTH=openrouter-api-key +# STACK_BENCH_OPENROUTER_API_KEY_FILE=${STACK_BENCH_STATE_ROOT}/secrets/openrouter_api_key + +# Setup emits immutable local sha256: values. Distributed releases use +# registry references ending in @sha256:<64 hex chars>. +STACK_BENCH_CONTROLLER_IMAGE=registry.example/stack-bench-controller@sha256:replace-with-release-digest +STACK_BENCH_BUILD_IMAGE=registry.example/stack-bench-build@sha256:replace-with-release-digest + +# Optional for internal campaigns and required for a distributed release +# campaign. The file must be below the appliance state root. +STACK_BENCH_RELEASE_MANIFEST=${STACK_BENCH_STATE_ROOT}/release/release.json diff --git a/tools/stack-bench/appliance/state-volume.ts b/tools/stack-bench/appliance/state-volume.ts new file mode 100644 index 00000000000..8de55d4223a --- /dev/null +++ b/tools/stack-bench/appliance/state-volume.ts @@ -0,0 +1,105 @@ +import { execFileSync } from 'node:child_process'; +import { chmodSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'; +import { join } from 'node:path'; +import { resolveContainerImage } from '../src/runtime/container-image.js'; +import { DATABASE_IMAGES } from '../src/stacks/database-containers.js'; + +export const STATE_VOLUME = 'stack-bench-state'; +type Docker = (args: readonly string[]) => string; +const docker: Docker = args => execFileSync('docker', [...args], { + encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'], timeout: args[0] === 'pull' ? 300_000 : 60_000, +}); + +/** The controller and Docker daemon see one native Linux path on every host OS. */ +export function prepareStateVolume(env: NodeJS.ProcessEnv = process.env, run: Docker = docker): string { + if (run(['version', '--format', '{{.Server.Os}}']).trim() !== 'linux') { + throw new Error('Stack Bench requires a Docker daemon running Linux containers'); + } + const inspect = (_command: string, args: readonly string[]) => run(args); + const controller = resolveContainerImage(env.STACK_BENCH_CONTROLLER_IMAGE + ?? 'stack-bench-controller:local', inspect).id; + const build = resolveContainerImage(env.STACK_BENCH_BUILD_IMAGE + ?? 'stack-bench-build:local', inspect).id; + for (const reference of Object.values(DATABASE_IMAGES)) { + try { resolveContainerImage(reference, inspect); } + catch { + run(['pull', '--platform', 'linux/amd64', reference]); + resolveContainerImage(reference, inspect); + } + } + run(['volume', 'create', STATE_VOLUME]); + const root = run(['volume', 'inspect', '--format', '{{.Mountpoint}}', STATE_VOLUME]).trim(); + if (!/^\/[A-Za-z0-9_./-]+$/.test(root) || root.split('/').includes('..')) { + throw new Error('Docker state volume has an invalid Linux mountpoint'); + } + run(['run', '--rm', '--platform', 'linux/amd64', '--network', 'none', '--mount', + `type=volume,source=${STATE_VOLUME},target=${root}`, '--entrypoint', 'node', controller, '-e', + 'const fs=require("node:fs"),p=require("node:path");' + + 'const root=process.argv[1];' + + 'for(const name of ["work","results/plans","results/run-presets","secrets","controller-home"])' + + 'fs.mkdirSync(p.join(root,name),{recursive:true,mode:0o700});' + + 'for(const [source,name] of [["campaign.example.json","reference-check.json"],["campaign.ecommerce-progression-reference.json","ecommerce-progression.json"],["campaign.demo.json","demo.json"]]) {' + + 'const target=p.join(root,"results/plans",name);if(!fs.existsSync(target))' + + 'fs.copyFileSync(p.join("/opt/stack-bench/appliance",source),target,fs.constants.COPYFILE_EXCL);}' + + 'const demo=p.join(root,"results/plans/paid-l1.json");if(!fs.existsSync(demo)){' + + 'const plan=JSON.parse(fs.readFileSync("/opt/stack-bench/appliance/campaign.paid-l1.json","utf8"));' + + 'plan.runtime.controllerImage=process.argv[2];plan.runtime.buildImage=process.argv[3];plan.state="frozen";' + + 'fs.writeFileSync(demo,JSON.stringify(plan,null,2)+"\\n",{flag:"wx",mode:0o600});}' + + 'const paid=JSON.parse(fs.readFileSync("/opt/stack-bench/appliance/campaign.paid-l1-l3.json","utf8"));' + + 'for(const [source,id,title] of [["campaign.paid-l1-l3.json","ecommerce-sequential","Ecommerce — sequential levels"],' + + '["campaign.ecommerce-progression-reference.json","ecommerce-progressive","Ecommerce — progressive features"],' + + '["campaign.ecommerce-progression-reference.json","ecommerce-single-build","Ecommerce — single build"]]){' + + 'const target=p.join(root,"results/run-presets",id+".json");if(fs.existsSync(target))continue;' + + 'const d=JSON.parse(fs.readFileSync(p.join("/opt/stack-bench/appliance",source),"utf8"));' + + 'd.id=id;d.title=title;d.state="frozen";d.agents=paid.agents;d.pricing=paid.pricing;' + + 'if(id==="ecommerce-single-build")d.mode.workSelection="all-at-once";' + + 'd.runtime.controllerImage=process.argv[2];d.runtime.buildImage=process.argv[3];' + + 'd.budgets=paid.budgets;d.repair.budget={total:0};d.parallelism=d.stacks.length;' + + 'if(id==="ecommerce-progressive"){d.budgets={attemptTimeoutMinutes:240,maxCostUsdPerAttempt:50};d.mode.retainPriorContracts=true;d.mode.unchangedFailureLimit=7;}' + + 'd.conditions=["neutral","neutral-no-sdk","neutral-dev","neutral-dev-no-sdk"].map(g=>({...d.conditions[0],id:g,guidanceProfile:g}));' + + 'fs.writeFileSync(target,JSON.stringify(d,null,2)+"\\n",{flag:"wx",mode:0o600});}', + root, controller, build]); + return [ + `STACK_BENCH_STATE_ROOT=${root}`, + `STACK_BENCH_CONTROLLER_IMAGE=${controller}`, + `STACK_BENCH_BUILD_IMAGE=${build}`, + 'STACK_BENCH_RUNNER_CAPACITY=dynamic', + 'STACK_BENCH_AGENT_AUTH=subscription-token', + `STACK_BENCH_CLAUDE_OAUTH_TOKEN_FILE=${root}/secrets/claude_subscription_token`, + `STACK_BENCH_ANTHROPIC_API_KEY_FILE=${root}/secrets/anthropic_api_key`, + `STACK_BENCH_OPENROUTER_API_KEY_FILE=${root}/secrets/openrouter_api_key`, + `STACK_BENCH_OPENAI_API_KEY_FILE=${root}/secrets/openai_api_key`, + `STACK_BENCH_CODEX_AUTH_FILE=${root}/secrets/codex_auth`, + 'STACK_BENCH_RELEASE_MANIFEST=', + '', + ].join('\n'); +} + +export function writeStateSecret(name: string | undefined, input: string, + root = '/state'): void { + if (!['claude_subscription_token', 'anthropic_api_key', 'openai_api_key', 'openrouter_api_key', 'codex_auth'].includes(name ?? '')) { + throw new Error('secret name must be claude_subscription_token, anthropic_api_key, openai_api_key, openrouter_api_key, codex_auth'); + } + let value = input.trim(); + if (name === 'codex_auth') { + try { value = JSON.stringify(JSON.parse(value)); } + catch { throw new Error('codex_auth must be valid JSON from Codex account login'); } + } + if (!value || /[\r\n]/.test(value)) { + throw new Error('secret must be one non-empty line'); + } + mkdirSync(join(root, 'secrets'), { recursive: true, mode: 0o700 }); + chmodSync(join(root, 'secrets'), 0o700); + writeFileSync(join(root, 'secrets', name!), `${value}\n`, { mode: 0o600 }); + chmodSync(join(root, 'secrets', name!), 0o600); +} + +export function stateVolumeCommand(command: string, args: string[]): void { + if (command === 'setup') { + if (args.length) throw new Error('setup accepts no arguments; configure image references through the environment'); + process.stdout.write(prepareStateVolume()); + } else { + if (args.length !== 1) throw new Error('set-secret requires exactly one secret name'); + writeStateSecret(args[0], readFileSync(0, 'utf8')); + } +} diff --git a/tools/stack-bench/backends/minimal/mongodb.md b/tools/stack-bench/backends/minimal/mongodb.md new file mode 100644 index 00000000000..a4a7e8d3c8a --- /dev/null +++ b/tools/stack-bench/backends/minimal/mongodb.md @@ -0,0 +1,21 @@ +# MongoDB + +Use MongoDB for the application data. Choose the libraries, architecture, and +project structure. + +## Connection + +| Setting | Value | +|---|---| +| `DATABASE_URL` | `` | +| Web application | `http://localhost:` | + +The MongoDB service is already running as a single-node replica set. Use the exact `DATABASE_URL`. Do not +start another MongoDB server, connect to another instance, or create another +database. Serve the complete application on ``. +Read `DATABASE_URL` from the process environment at startup. It can change between +launches; do not embed it in source or override it with a saved value. +Create `/app/start.sh`. From a clean source checkout, it must install +dependencies, build the complete application, and start it on ``. +The script must not change source files. Leave the application running when the +work is complete. diff --git a/tools/stack-bench/backends/minimal/postgres.md b/tools/stack-bench/backends/minimal/postgres.md new file mode 100644 index 00000000000..1a078206cf4 --- /dev/null +++ b/tools/stack-bench/backends/minimal/postgres.md @@ -0,0 +1,21 @@ +# PostgreSQL + +Use PostgreSQL for the application data. Choose the libraries, architecture, +and project structure. + +## Connection + +| Setting | Value | +|---|---| +| `DATABASE_URL` | `` | +| Web application | `http://localhost:` | + +The PostgreSQL service is already running. Use the exact `DATABASE_URL`. Do not +start another PostgreSQL server, connect to another instance, or create another +database. Serve the complete application on ``. +Read `DATABASE_URL` from the process environment at startup. It can change between +launches; do not embed it in source or override it with a saved value. +Create `/app/start.sh`. From a clean source checkout, it must install +dependencies, build the complete application, and start it on ``. +The script must not change source files. Leave the application running when the +work is complete. diff --git a/tools/stack-bench/backends/minimal/spacetime.md b/tools/stack-bench/backends/minimal/spacetime.md new file mode 100644 index 00000000000..508dbe353b5 --- /dev/null +++ b/tools/stack-bench/backends/minimal/spacetime.md @@ -0,0 +1,28 @@ +# SpacetimeDB + +Use SpacetimeDB for the application data. Put the TypeScript module in the +required directory below. Choose the schema, libraries, architecture, and the +rest of the project structure. + +## Connection + +Use the connection settings below. + +| Setting | Value | +|---|---| +| Server URI | `` | +| Module name | `` | +| SpacetimeDB CLI | `` | +| TypeScript SDK package | `` | +| Module source directory | `/app/backend/spacetimedb` | +| Web application | `http://localhost:` | + +Publish only the named module to the exact server URI. Local publish and +development commands must use `--yes`. Do not pipe confirmation input, publish +anonymously, or use the hosted service. Create `/app/start.sh`. From a clean +source checkout, it must install dependencies, build the complete application, +and start it on ``. The script must not change source files. Leave +the application running when the work is complete. + +The included TypeScript server and client skills provide SDK guidance. +CLI `--help` is available for command syntax. diff --git a/tools/stack-bench/backends/model-free-stub.md b/tools/stack-bench/backends/model-free-stub.md new file mode 100644 index 00000000000..7a83d0e4bc2 --- /dev/null +++ b/tools/stack-bench/backends/model-free-stub.md @@ -0,0 +1,4 @@ +# Model-free service + +Use the supplied service. Leave the app running on the assigned client port +when the work is complete. diff --git a/tools/stack-bench/backends/mongodb.md b/tools/stack-bench/backends/mongodb.md new file mode 100644 index 00000000000..48ae7319b5f --- /dev/null +++ b/tools/stack-bench/backends/mongodb.md @@ -0,0 +1,50 @@ +# Backend: MongoDB + +An Express API server with Socket.io for live updates, Mongoose over MongoDB, +and a React client. + +## Layout + +``` +/ + server/ + package.json express, socket.io, mongoose, dotenv, tsx + .env DATABASE_URL and PORT + src/models.ts Mongoose schemas and models + src/index.ts Express routes, Socket.io handlers + client/ + package.json react, react-dom, vite, socket.io-client + vite.config.ts server.port , proxy /api and /socket.io to + index.html + src/main.tsx + src/App.tsx +``` + +## Deploy + +```bash +cd server && npm install && npm run dev # on +cd client && npm install && npm run dev # on +``` + +Mongoose creates collections on first write; there is no migration step. + +The server prints to the terminal running `npm run dev`; it restarts on save, +so a code change is live without redeploying. + +Keep existing application data when you change the schema. Do not drop +collections during upgrades or repairs. + +## Configuration + +| Setting | Value | +|---|---| +| `DATABASE_URL` | `` | +| API server port | `` | +| Client dev server | `` | + +Use this exact `DATABASE_URL`. Do not point at another MongoDB instance. +Read `DATABASE_URL` from the process environment at startup. It can change between +launches; do not embed it in source or override it with a saved value. + +The supplied database is a single-node replica set. diff --git a/tools/stack-bench/backends/postgres.md b/tools/stack-bench/backends/postgres.md new file mode 100644 index 00000000000..b605b9aeaf7 --- /dev/null +++ b/tools/stack-bench/backends/postgres.md @@ -0,0 +1,50 @@ +# Backend: PostgreSQL + +An Express API server with Socket.io for live updates, Drizzle ORM over +PostgreSQL, and a React client. + +## Layout + +``` +/ + server/ + package.json express, socket.io, drizzle-orm, pg, dotenv, tsx + .env DATABASE_URL and PORT + drizzle.config.ts + src/schema.ts Drizzle table definitions + src/index.ts Express routes, Socket.io handlers + client/ + package.json react, react-dom, vite, socket.io-client + vite.config.ts server.port , proxy /api and /socket.io to + index.html + src/main.tsx + src/App.tsx +``` + +## Deploy + +```bash +cd server && npm install && npx drizzle-kit push && npm run dev # on +cd client && npm install && npm run dev # on +``` + +Re-run `npx drizzle-kit push` after any schema change. + +The server prints to the terminal running `npm run dev`; it restarts on save, +so a code change is live without redeploying. + +Keep existing application data when you change the schema. Do not drop or +recreate tables during upgrades or repairs. + +## Configuration + +| Setting | Value | +|---|---| +| `DATABASE_URL` | `` | +| API server port | `` | +| Client dev server | `` | + +Use this exact `DATABASE_URL`. Do not point at another PostgreSQL instance and do +not create databases outside it. +Read `DATABASE_URL` from the process environment at startup. It can change between +launches; do not embed it in source or override it with a saved value. diff --git a/tools/stack-bench/backends/spacetime.md b/tools/stack-bench/backends/spacetime.md new file mode 100644 index 00000000000..250587f88fe --- /dev/null +++ b/tools/stack-bench/backends/spacetime.md @@ -0,0 +1,80 @@ +# Backend: SpacetimeDB + +The database runs your server logic. There is no separate API server and no ORM: +tables and reducers are a WASM module you publish, and the client subscribes to +tables and calls reducers over a live connection. + +## Layout + +``` +/ + backend/spacetimedb/ + package.json { "type": "module", dependencies: { "spacetimedb": "" }, + devDependencies: { "typescript": "~5.6.2" } } ← required; the build runs tsc from node_modules + tsconfig.json + src/schema.ts tables and indexes + src/index.ts reducers and lifecycle hooks + client/ + package.json react, react-dom, vite, and "spacetimedb": "" + vite.config.ts server.port must be + index.html + src/config.ts MODULE_NAME and SPACETIMEDB_URI + src/main.tsx React entry + src/App.tsx + src/module_bindings/ generated; never edit by hand +``` + +## Deploy + +Publish the module, then regenerate the client bindings from it: + +```bash + publish --module-path backend/spacetimedb -s --yes + generate --lang typescript --out-dir client/src/module_bindings --module-path backend/spacetimedb +``` + +**While iterating, run development mode instead of republishing by hand.** It +watches the module and automatically rebuilds, publishes, and regenerates the +client bindings on every save: + +```bash + dev --module-path backend/spacetimedb -s --yes +``` + +Leave it running in the background while you work. The manual commands below +are for one-off publishes and for the first deploy. + +Republish after any server change, and regenerate after any schema change. + +Keep existing application data when you change the schema. + +Always use `--yes` for local publish and development commands. It selects the +CLI's non-interactive authentication flow for the target server. Do not pipe +`y` into the command and do not publish anonymously. Use the same local +identity for every publish to the named module. + +Then start the client: + +```bash +cd client && npm install && npm run dev +``` + +` logs -s ` shows module output, including reducer errors. + +To inspect stored data while debugging: + +```bash + sql "SELECT * FROM item LIMIT 5" -s +``` + +## Configuration + +| Setting | Value | +|---|---| +| Server URI | `` | +| Module name | `` | +| Client dev server | `` | + +The SDK reference for writing modules and clients is in the skill documents +included with these instructions. Follow them for API specifics: import paths, +type builders, accessors and context typing. diff --git a/tools/stack-bench/backends/workflows/spacetime-dev.md b/tools/stack-bench/backends/workflows/spacetime-dev.md new file mode 100644 index 00000000000..7c281dd2dac --- /dev/null +++ b/tools/stack-bench/backends/workflows/spacetime-dev.md @@ -0,0 +1,44 @@ +--- +name: spacetime-dev +description: Use the SpacetimeDB development watcher while implementing an application. +--- + +# Development workflow + +Use `spacetime dev` while implementing and repairing the application. Keep one +watcher running for the assigned database. It builds module changes, publishes +them, and generates client bindings. Use the supplied CLI, server URI, database +name, and module directory. See the CLI skill for command syntax. + +Use the supplied server URL directly; do not register a server nickname or +change the CLI login. Use a project configuration with both publish and generate +targets. For example, in `/app/spacetime.json`, replacing the server, database, +and client directory with the supplied settings and your actual paths: + +```json +{ + "server": "http://SERVER:PORT", + "database": "DATABASE", + "module-path": "backend/spacetimedb", + "generate": [ + { "language": "typescript", "out-dir": "frontend/src/module_bindings" } + ] +} +``` + +From `/app`, run the supplied CLI with `dev --yes --delete-data=never +--server-only`. Start the web client separately. With these configured targets, +omit `--module-path`, `--project-path`, and `--module-bindings-path` flags. +Paths in this example are relative to the project directory. +Do not run competing publish commands or watchers. If bindings generation is skipped, +correct the generate target before continuing. + +Wait for the initial publish and bindings to succeed before opening the app. +After a module edit, check that the watcher published it successfully before +checking app behavior. Fix watcher errors; do not assume that the live module is current. +Restart the watcher if it exited or its configuration changed. + +Keep `/app/start.sh` able to build and start the complete application from a +clean source checkout without this development session. Stop the watcher before +checking that startup path. One-shot commands remain appropriate for that script +and for diagnosing a watcher failure. diff --git a/tools/stack-bench/backends/workflows/spacetime-managed-dev.md b/tools/stack-bench/backends/workflows/spacetime-managed-dev.md new file mode 100644 index 00000000000..9b4b4c39960 --- /dev/null +++ b/tools/stack-bench/backends/workflows/spacetime-managed-dev.md @@ -0,0 +1,24 @@ +--- +name: spacetime-managed-dev +description: Use the supplied command to manage the SpacetimeDB development watcher. +--- + +# Development workflow + +Development watcher support is available at `/deps/spacetime-dev`. It has not +started yet. Create the module and `/app/spacetime.json` first. Configure the +supplied server URL and database name, your `module-path`, and TypeScript +`generate` targets with their `out-dir` paths. Keep these paths inside `/app`. +This helper supports one database per application. See the CLI skill for configuration syntax. + +Run `/deps/spacetime-dev start`. It starts one watcher with data deletion disabled. +Repeated calls report the existing watcher. Run `/deps/spacetime-dev status` to +check startup, and read the reported log for build or publish errors. +"Starting" does not mean the initial publish has completed. "Running" confirms +the initial publish and bindings; later edits can still fail, so check the log. +Start the frontend separately. Do not start another watcher or competing publisher. + +Use `/deps/spacetime-dev stop` before changing configuration or testing a clean +startup, then `start` again when needed. An exited watcher is not restarted +automatically. Keep `/app/start.sh` able to build and start the complete application +without this development session. Container cleanup stops the watcher. diff --git a/tools/stack-bench/commands/agent.ts b/tools/stack-bench/commands/agent.ts new file mode 100644 index 00000000000..235799cf66b --- /dev/null +++ b/tools/stack-bench/commands/agent.ts @@ -0,0 +1,996 @@ +#!/usr/bin/env node + +import { randomUUID } from 'node:crypto'; +import { execFileSync } from 'node:child_process'; +import type { ExecFileSyncOptionsWithStringEncoding } from 'node:child_process'; +import { readFileSync, writeFileSync, mkdirSync, existsSync, realpathSync, + openSync, readSync, closeSync, readdirSync } from 'node:fs'; +import { join, dirname, resolve, relative, isAbsolute, sep } from 'node:path'; +import { homedir } from 'node:os'; +import { fileURLToPath } from 'node:url'; +import { parseArgs as parseNodeArgs } from 'node:util'; +import { loadTrack, levelPrompt, appendix, suitesFor, dbName, moduleName, portsFor, + DEFAULT_TRACK, TRACK_MANIFEST_FILE } from '../src/composition/tracks.js'; +import type { Track, TrackDefinition } from '../src/composition/tracks.js'; +import type { BackendLease } from '../src/runtime/backend-lease.js'; +import { resolveRecipeRelease } from '../src/composition/recipe-release.js'; +import { parseGuidanceMode, resolveDefaultGuidanceForStack, type GuidanceMode, + type ResolvedGuidanceDocument, type ResolvedSkills } + from '../src/campaigns/condition-compiler.js'; +import type { RecipeBinding, RecipeRequest } from '../src/composition/recipe-release.js'; +import { createBoundRecipeTaskRequest, resolveBoundRecipeTaskRequest } from '../src/composition/recipe-selection.js'; +import { agentVisibleContractText, assertAgentVisibleText } + from '../src/composition/agent-visible-contract.js'; +import { DEFAULT_SPACETIME_SERVER_URI, leaseFromEnv } from '../src/runtime/backend-lease.js'; +import { CODING_CONTAINER_APP_ROOT, CODING_CONTAINER_BUG_REPORT_FILE, + CODING_CONTAINER_RELEASE_DEPS_ROOT, CODING_CONTAINER_SPACETIME_CLI, + CODING_CONTAINER_SPACETIME_PACKAGE } + from '../src/runtime/coding-container-policy.js'; +import { resolveContainerImage } from '../src/runtime/container-image.js'; +import { hashDirectory, sessionProvenance, sha256 } from '../src/evidence/provenance.js'; +import type { StackRunPorts } from '../src/stacks/stack-adapter-contract.js'; +import { STACK_ADAPTER_REGISTRY } from '../src/stacks/stack-adapters.js'; +import { attemptDatabaseUrl } from '../src/stacks/hosted-database-identity.js'; +import { requireLeasedDatabase, requireLeasedSpacetime } + from '../src/stacks/backend-reset-guard.js'; +import { DEFAULT_BUILD_IMAGE } from '../src/composition/product-config.js'; +import { dockerMountArguments } from '../src/runtime/container-mount.js'; +import { normalizePromptText, readAgentSkillDocuments, selectAgentSkills } from '../src/agents/agent-materials.js'; +import { codingSessionFailure, DEFAULT_THROTTLE_MAX_WAIT_MS, providerSessionFailure, + runCodingSessionWithRetries, PROVIDER_CONTINUATION_MESSAGE } from '../src/agents/coding-session-retry.js'; +import { captureNativeContinuation } from '../src/agents/provider-native-continuation.js'; +import { campaignProviderContinuationContext, persistCampaignProviderInvocation, + waitForCampaignProviderContinuation } from '../src/campaigns/campaign-provider-continuation.js'; +import type { CodingSessionRetryResult } from '../src/agents/coding-session-retry.js'; +import { AGENT_PROCESS_TIMEOUT_MS } from '../src/agents/coding-session-timeouts.js'; +import { assertNewOrEmptyDirectory } from '../src/runtime/path-safety.js'; +import { resolveContainerAuth } from '../container/container-auth.js'; +import { CODING_PROVIDERS, parseCodingProvider } from '../container/coding-providers.js'; +import { validateProviderRoute, validateProviderOutputLimit } from '../src/agents/agent-adapter-contract.js'; +import { PRICING_UNIT, validatePricingAuthority } + from '../src/evidence/pricing-authority.js'; +import type { PricingAuthority } from '../src/evidence/pricing-authority.js'; + +import { STACK_BENCH_ROOT as ROOT, compiledEntrypoint } from '../src/package-root.js'; +const REPO = resolve(ROOT, '..', '..'); +const CONTROL_COMMAND_TIMEOUT_MS = 120_000; +const DEFAULT_CODING_INTERRUPTION_RETRIES = 2; + +type UnknownRecord = Record; +interface PromptMaterials { + skillsText?: string; + requirementText?: string; + contractText?: string; + startingCatalog?: string; +} + +type RecipeTaskRequest = Parameters[1] & { + recipe?: Exclude; +}; + +type AgentMode = 'build' | 'upgrade' | 'fix' | 'resume'; + +interface AgentArgs { + provider: keyof typeof CODING_PROVIDERS; + providerRoute?: string; + maxOutputTokens?: number; + mode: AgentMode; + backend: string; + app: string; + level: number; + runIndex: number; + model: string; + guidance: GuidanceMode; + productionQuality?: boolean; + track: string; + pricing: Readonly | null; + guidanceDocument?: ResolvedGuidanceDocument; + credentialAliases?: Readonly>; + recipe?: string; + recipeTask?: RecipeTaskRequest; + thinking?: string; + maxBudgetUsd?: number; + skills?: string[]; + skillIdentity?: ResolvedSkills; + apiKey?: string; + printPrompt?: boolean; +} + +interface ThinkingVolume { + blocks: number; + signatureBytes: number; + bytesPerBlock: number; +} + +interface SessionUsage { + input_tokens?: number; + output_tokens?: number; + cache_creation_input_tokens?: number; + cache_read_input_tokens?: number; +} + +const isRecord = (value: unknown): value is UnknownRecord => + value !== null && typeof value === 'object' && !Array.isArray(value); + +const stringValue = (value: unknown): string | null => typeof value === 'string' ? value : null; + +function stringArray(value: string, option: string): string[] { + const parsed: unknown = JSON.parse(value); + if (!Array.isArray(parsed) || parsed.some(item => typeof item !== 'string')) { + throw new Error(`${option} must be an array of strings`); + } + return parsed; +} + +function sessionUsage(value: unknown): SessionUsage { + return isRecord(value) ? { + input_tokens: typeof value.input_tokens === 'number' ? value.input_tokens : undefined, + output_tokens: typeof value.output_tokens === 'number' ? value.output_tokens : undefined, + cache_creation_input_tokens: typeof value.cache_creation_input_tokens === 'number' + ? value.cache_creation_input_tokens : undefined, + cache_read_input_tokens: typeof value.cache_read_input_tokens === 'number' + ? value.cache_read_input_tokens : undefined, + } : {}; +} + +// Use only the benchmark-owned SpacetimeDB host. +const STDB_URI = process.env.STACK_BENCH_STDB_URI ?? DEFAULT_SPACETIME_SERVER_URI; + +// Test the CLI and SDK from this checkout. +const LOCAL_CLI = join(REPO, 'target', 'release', 'spacetimedb-cli.exe'); +const STDB_BIN = process.env.SPACETIME_BIN ?? (existsSync(LOCAL_CLI) ? LOCAL_CLI : 'spacetime'); +const LOCAL_PKG = process.env.STDB_PACKAGE ?? join(REPO, 'crates', 'bindings-typescript'); + +const fwd = (path: string): string => path.split('\\').join('/'); + +// Keep the provider's default thinking budget unless an experiment selects one +// explicitly. The run records observed reasoning volume so default changes are +// visible in the evidence. +const THINKING_TOKENS = process.env.STACK_BENCH_THINKING ?? null; + +const EFFORT = process.env.STACK_BENCH_EFFORT ?? 'high'; + +const IMAGE = process.env.STACK_BENCH_IMAGE ?? DEFAULT_BUILD_IMAGE; + +// Containers reach host services through this address. App ports remain local. +export function hostServiceAddress(env: NodeJS.ProcessEnv = process.env): string { + return env.STACK_BENCH_HOST_ALIAS + ?? (env.STACK_BENCH_APPLIANCE === '1' ? '127.0.0.1' : 'host.docker.internal'); +} + +const HOST_ADDR = hostServiceAddress(); +const hostUrl = (url: string): string => url.replace(/127\.0\.0\.1|localhost/g, HOST_ADDR); + +const C_BIN = CODING_CONTAINER_SPACETIME_CLI; + +// The container requires the Linux CLI from this checkout. +const LINUX_CLI = process.env.STACK_BENCH_LINUX_CLI + ?? join(ROOT, 'container', 'bin', 'spacetimedb-cli'); + +// The provider CLI keeps one JSONL transcript per session under its project +// directory for the application path. +function transcriptFile(appDir: string, sessionId: string): string | null { + const store = join(homedir(), '.claude', 'projects'); + if (!existsSync(store)) return null; + const want = resolve(appDir).replace(/[\\/:]/g, '-').toLowerCase(); + const dir = readdirSync(store).find(d => { + const n = d.toLowerCase(); + return n === want || n === want.replace(/^-+/, ''); + }); + const file = dir && join(store, dir, `${sessionId}.jsonl`); + return file && existsSync(file) ? file : null; +} + +// The model ids the provider actually served. The requested name is an alias +// that can resolve to different snapshots over time; the transcript records +// what answered each request. +function transcriptModels(appDir: string, sessionIds: readonly (string | null | undefined)[]): string[] { + const models = new Set(); + for (const sessionId of new Set(sessionIds.filter((id): id is string => Boolean(id)))) { + try { + const file = transcriptFile(appDir, sessionId); + if (!file) continue; + for (const line of readFileSync(file, 'utf8').split('\n')) { + if (!line.includes('"model"')) continue; + let record: unknown; + try { record = JSON.parse(line); } catch { continue; } + if (!isRecord(record) || !isRecord(record.message)) continue; + const model = stringValue(record.message.model); + if (model) models.add(model); + } + } catch { /* an unreadable transcript leaves the list shorter, never wrong */ } + } + return [...models].sort(); +} + +// The transcript exposes reasoning blocks and signature bytes, not reasoning tokens. +function thinkingVolume(appDir: string, sessionId: string | null | undefined): ThinkingVolume | null { + if (!sessionId) return null; + try { + const file = transcriptFile(appDir, sessionId); + if (!file) return null; + + let blocks = 0, bytes = 0; + for (const line of readFileSync(file, 'utf8').split('\n')) { + if (!line.includes('"thinking"')) continue; // cheap filter before parsing + let record: unknown; + try { record = JSON.parse(line); } catch { continue; } + if (!isRecord(record) || !isRecord(record.message) + || !Array.isArray(record.message.content)) continue; + for (const content of record.message.content) { + if (!isRecord(content) || content.type !== 'thinking') continue; + blocks++; + bytes += stringValue(content.signature)?.length ?? 0; + } + } + return { blocks, signatureBytes: bytes, + bytesPerBlock: blocks ? Math.round(bytes / blocks) : 0 }; + } catch { return null; } +} + +function combinedThinkingVolume(appDir: string, sessionIds: readonly (string | null | undefined)[]): ThinkingVolume | null { + const volumes: ThinkingVolume[] = [...new Set(sessionIds.filter((id): id is string => Boolean(id)))] + .map(id => thinkingVolume(appDir, id)).filter((item): item is ThinkingVolume => item !== null); + if (!volumes.length) return null; + const blocks = volumes.reduce((sum, item) => sum + item.blocks, 0); + const signatureBytes = volumes.reduce((sum, item) => sum + item.signatureBytes, 0); + return { blocks, signatureBytes, + bytesPerBlock: blocks ? Math.round(signatureBytes / blocks) : 0 }; +} + + +// Record the Linux CLI executed by the container. The host and container +// binaries can change independently and must not share an identity. +function linuxSpacetimeVersion(image: string): { commit: string | null; binarySha256: string | null; raw: string } { + try { + const releaseVolume = process.env.STACK_BENCH_RELEASE_DEPS_VOLUME?.trim() || null; + const mountArgs = releaseVolume + ? dockerMountArguments({ kind: 'volume', source: releaseVolume, + target: CODING_CONTAINER_RELEASE_DEPS_ROOT, readOnly: true }) + : ['-v', `${LINUX_CLI}:${CODING_CONTAINER_SPACETIME_CLI}:ro`]; + const entrypoint = releaseVolume + ? `${CODING_CONTAINER_RELEASE_DEPS_ROOT}/spacetimedb-cli` + : CODING_CONTAINER_SPACETIME_CLI; + const out = execFileSync('docker', + ['run', '--rm', ...mountArgs, '--entrypoint', entrypoint, image, '--version'], + { encoding: 'utf8', stdio: 'pipe', env: { ...process.env, MSYS_NO_PATHCONV: '1' }, + timeout: CONTROL_COMMAND_TIMEOUT_MS }); + const commit = out.match(/Commit:\s*([0-9a-f]+)/i)?.[1] ?? null; + return { commit, binarySha256: sha256(readFileSync(LINUX_CLI)), + raw: out.trim().split(/\r?\n/).slice(0, 2).join(' ') }; + } catch { return { commit: null, binarySha256: null, raw: 'unknown' }; } +} + +function bindingsIdentity(pkgDir: string): { package: string; sourceSha256: string | null; sourceFiles: number } { + try { + const p = JSON.parse(readFileSync(join(pkgDir, 'package.json'), 'utf8')); + const source = hashDirectory(pkgDir, { exclude: name => + /(^|\/)(node_modules|dist|target)(\/|$)/.test(name) }); + return { package: `${p.name}@${p.version}`, sourceSha256: source.sha256, + sourceFiles: source.files.length }; + } catch { return { package: 'unknown', sourceSha256: null, sourceFiles: 0 }; } +} + +// The CLI version inside the build image. Read by running it, not by trusting +// the tag: the image is pinned by ARG and a tag can be moved. +function imageCliVersion(image: string, executable: string): string { + try { + return execFileSync('docker', ['run', '--rm', '--entrypoint', executable, image, '--version'], + { encoding: 'utf8', stdio: 'pipe', env: { ...process.env, MSYS_NO_PATHCONV: '1' }, + timeout: CONTROL_COMMAND_TIMEOUT_MS }).trim(); + } catch { return 'unknown'; } +} + +function imageNodeVersion(image: string): string { + try { + return execFileSync('docker', ['run', '--rm', '--entrypoint', 'node', image, '--version'], + { encoding: 'utf8', stdio: 'pipe', env: { ...process.env, MSYS_NO_PATHCONV: '1' }, + timeout: CONTROL_COMMAND_TIMEOUT_MS }).trim(); + } catch { return 'unknown'; } +} + +function containerImage(name: string): { reference: string; imageId: string | null | undefined } { + try { + const out = execFileSync('docker', ['inspect', '-f', '{{.Config.Image}} {{.Image}}', name], + { encoding: 'utf8', stdio: 'pipe', timeout: CONTROL_COMMAND_TIMEOUT_MS }).trim(); + const [reference, imageId] = out.split(/\s+/, 2); + return { reference: reference ?? '', imageId }; + } catch { return { reference: 'unknown', imageId: null }; } +} + +// Record ambient provider configuration that can change model behaviour while +// replacing credential values with presence markers. +function ambientEnv(): Record { + const seen: Record = {}; + for (const [k, v] of Object.entries(process.env)) { + if (!/^(CLAUDE|ANTHROPIC|OPENAI|OPENROUTER|CODEX|MAX_THINKING|DISABLE_AUTOUPDATER|FORCE_PROMPT)/.test(k)) continue; + // Never record a credential, only that one was present. + seen[k] = /KEY|TOKEN|SECRET|AUTH/i.test(k) ? '' : v; + } + return seen; +} + +export function parseAgentArgs(argv: readonly string[]): AgentArgs { + const strings = ['provider', 'provider-route', 'max-output-tokens', 'mode', 'track', 'backend', 'level', 'app', 'run-index', 'model', + 'pricing-json', 'guidance', 'guidance-document-json', 'credential-aliases-json', + 'recipe', 'recipe-task-json', 'thinking', 'max-budget-usd', 'skills', 'skills-json', + 'skill-identity-json', 'api-key'] as const; + const { values: rawValues } = parseNodeArgs({ args: [...argv.slice(2)], options: Object.fromEntries([ + ...strings.map(name => [name, { type: 'string' as const }]), + ['print-prompt', { type: 'boolean' as const }], + ['production-quality', { type: 'boolean' as const }], + ['no-production-quality', { type: 'boolean' as const }], + ]), strict: true, allowPositionals: false }); + const values = rawValues as Partial> + & { 'print-prompt'?: boolean; 'production-quality'?: boolean; 'no-production-quality'?: boolean }; + if (values['production-quality'] && values['no-production-quality']) throw new Error('choose only one production-quality flag'); + const mode = values.mode; + if (mode !== 'build' && mode !== 'upgrade' && mode !== 'fix' && mode !== 'resume') { + throw new Error('--mode must be build, upgrade, fix, or resume'); + } + const backend = values.backend; + const app = values.app; + if (!backend || !app) { + throw new Error('usage: node dist/commands/agent.js --mode build|upgrade|fix|resume ' + + '--backend --app [--level ]'); + } + const level = values.level === undefined ? 1 : Number(values.level); + if (!Number.isSafeInteger(level) || level < 1) { + throw new Error('--level must be a positive integer'); + } + const runIndex = values['run-index'] === undefined ? 0 : Number(values['run-index']); + if (!Number.isSafeInteger(runIndex) || runIndex < 0) { + throw new Error('--run-index must be a non-negative integer'); + } + const provider = parseCodingProvider(values.provider ?? 'anthropic'); + const codingProvider = CODING_PROVIDERS[provider]; + if (codingProvider.requiresBudget && !values.model) throw new Error(`--model is required for ${provider}`); + if (codingProvider.executable !== 'claude' && values.thinking) { + throw new Error(`${provider} uses STACK_BENCH_EFFORT, not --thinking`); + } + const providerRoute = validateProviderRoute(provider, values['provider-route']); + const maxOutputTokens = validateProviderOutputLimit(provider, + values['max-output-tokens'] === undefined ? undefined : Number(values['max-output-tokens'])); + const model = values.model ?? 'claude-sonnet-5'; + const maxBudgetUsd = values['max-budget-usd'] === undefined + ? undefined : Number(values['max-budget-usd']); + if (maxBudgetUsd !== undefined && (!Number.isFinite(maxBudgetUsd) || maxBudgetUsd <= 0)) { + throw new Error('--max-budget-usd must be a positive number'); + } + if (values.skills !== undefined && values['skills-json'] !== undefined) { + throw new Error('--skills and --skills-json cannot be used together'); + } + const skills = values.skills?.split(',').map(skill => skill.trim()).filter(Boolean) + ?? (values['skills-json'] === undefined ? undefined + : stringArray(values['skills-json'], '--skills-json')); + let pricing = values['pricing-json'] === undefined + ? undefined : validatePricingAuthority(JSON.parse(values['pricing-json']), { at: '--pricing-json' }); + if (pricing === undefined && maxBudgetUsd !== undefined) { + const rates = CODING_PROVIDERS[provider].rates(model); + if (!rates) throw new Error(`no default pricing is recorded for model ${model}`); + pricing = validatePricingAuthority({ unit: PRICING_UNIT, rates }, + { at: 'default pricing' }); + } + return { provider, ...(providerRoute ? { providerRoute } : {}), mode, backend, app, level, runIndex, model, + ...(maxOutputTokens ? { maxOutputTokens } : {}), + guidance: parseGuidanceMode(values.guidance ?? 'prescribed'), + productionQuality: mode !== 'resume' && !values['no-production-quality'], + track: values.track ?? DEFAULT_TRACK, pricing: pricing ?? null, + ...(values['guidance-document-json'] ? { + guidanceDocument: JSON.parse(values['guidance-document-json']) as ResolvedGuidanceDocument, + } : {}), + ...(values['credential-aliases-json'] ? { + credentialAliases: JSON.parse(values['credential-aliases-json']) as Record, + } : {}), + ...(values.recipe ? { recipe: values.recipe } : {}), + ...(values['recipe-task-json'] ? { + recipeTask: JSON.parse(values['recipe-task-json']) as RecipeTaskRequest, + } : {}), + ...(values.thinking ? { thinking: values.thinking } : {}), + ...(maxBudgetUsd !== undefined ? { maxBudgetUsd } : {}), + ...(skills ? { skills } : {}), + ...(values['skill-identity-json'] ? { + skillIdentity: validateSkillIdentity(JSON.parse(values['skill-identity-json'])), + } : {}), + ...(values['api-key'] ? { apiKey: values['api-key'] } : {}), + ...(values['print-prompt'] ? { printPrompt: true } : {}) }; +} + +const dbUrl = (backend: string, runIndex: number, dbPort: number | null, track: Track): string | null => { + const adapter = STACK_ADAPTER_REGISTRY.get(backend); + if (adapter.id === 'spacetime' || adapter.id === 'stub') return null; + if (!dbPort) throw new Error(`${backend} has no assigned database port`); + if (process.env.STACK_BENCH_APPLIANCE === '1' && process.env.STACK_BENCH_LEASE) { + const { lease } = leaseFromEnv(process.env, { backend, active: true }); + if (lease.resources.network) return attemptDatabaseUrl({ backend, + database: lease.resources.database!, ownershipToken: lease.ownershipToken }); + } + return adapter.agent.connectionUrl({ dbPort, database: dbName(track, runIndex), hostUrl }); +}; + +// Create the leased database before the app connects. A build clears its schema. +// A reset between suites preserves the schema required by the running app. +type DatabasePreparationLease = BackendLease; + +type DatabaseCommandOptions = Pick; + +type DatabaseCommandExecutor = (command: string, args: readonly string[], + options: DatabaseCommandOptions) => string; + +const databaseCommandExecutor: DatabaseCommandExecutor = (command, args, options) => + String(execFileSync(command, args, { ...options, encoding: 'utf8' })); + +interface DatabasePreparationOptions { + exec?: DatabaseCommandExecutor; + stdbBin?: string; + lease?: DatabasePreparationLease; +} + +export function ensureDatabase(backend: string, runIndex: number, dbPort: number | null, + track: Pick, wipe = false, + { exec = databaseCommandExecutor, stdbBin = STDB_BIN, lease: suppliedLease }: DatabasePreparationOptions = {}) { + const lease = suppliedLease ?? leaseFromEnv(process.env, { backend, active: true }).lease; + if (lease.runIndex !== runIndex || lease.track !== track.name) { + throw new Error(`backend lease ${lease.runId} belongs to ${lease.track}/run${lease.runIndex}, ` + + `not ${track.name}/run${runIndex}`); + } + const expectedName = dbName(track, runIndex); + const name = lease.resources.database ?? expectedName; + const input = { name, expectedName, wipe, exec, cli: stdbBin, + expectedServerUri: STDB_URI, expectedModule: moduleName(track, runIndex), dbPort }; + const adapter = STACK_ADAPTER_REGISTRY.get(backend); + if (adapter.id === 'postgres' || adapter.id === 'mongodb') { + return adapter.database.prepare({ ...input, lease: requireLeasedDatabase(lease) }); + } + if (adapter.id === 'spacetime') { + return adapter.database.prepare({ ...input, lease: requireLeasedSpacetime(lease) }); + } + return adapter.database.prepare({ name }); +} + +// Prescribed guidance chooses an implementation stack. Neutral guidance gives +// only stack access facts and the selected API references. +export function readBackendGuidanceDocument( + document: ResolvedGuidanceDocument | undefined, + fallbackRelativePath: string, +): string { + if (typeof fallbackRelativePath !== 'string' || !fallbackRelativePath) { + throw new Error('backend guidance fallback path is required'); + } + if (document !== undefined) { + const fields = new Set(['path', 'sha256', 'bytes', 'applicationInterface']); + if (!document || typeof document !== 'object' || Array.isArray(document) + || Object.keys(document).some(field => !fields.has(field)) + || typeof document.path !== 'string' || !document.path || isAbsolute(document.path) + || document.path.includes('\\') + || !/^[a-f0-9]{64}$/.test(document.sha256) + || !Number.isSafeInteger(document.bytes) || document.bytes < 0 + || !['http', 'reducer'].includes(document.applicationInterface)) { + throw new Error('campaign guidance document identity is invalid'); + } + } + const root = realpathSync(ROOT); + const candidate = resolve(root, document?.path ?? fallbackRelativePath); + const candidateRel = relative(root, candidate); + if (candidateRel === '..' || candidateRel.startsWith(`..${sep}`) || isAbsolute(candidateRel)) { + throw new Error('campaign guidance document escapes the Stack Bench root'); + } + const selectedPath = realpathSync(candidate); + const resolvedRel = relative(root, selectedPath); + if (resolvedRel === '..' || resolvedRel.startsWith(`..${sep}`) || isAbsolute(resolvedRel)) { + throw new Error('campaign guidance document resolves outside the Stack Bench root'); + } + const bytes = Buffer.from(normalizePromptText(readFileSync(selectedPath, 'utf8')), 'utf8'); + if (document && (sha256(bytes) !== document.sha256 || bytes.length !== document.bytes)) { + throw new Error(`campaign guidance document changed after compilation: ${document.path}`); + } + return bytes.toString('utf8'); +} + +function validateSkillIdentity(value: unknown): ResolvedSkills { + const fields = new Set(['ids', 'sha256', 'bytes']); + if (!isRecord(value) || Object.keys(value).some(field => !fields.has(field)) + || !Array.isArray(value.ids) || new Set(value.ids).size !== value.ids.length + || value.ids.some(id => typeof id !== 'string' || !/^[a-z][a-z0-9-]*$/.test(id)) + || typeof value.sha256 !== 'string' || !/^[a-f0-9]{64}$/.test(value.sha256) + || !Number.isSafeInteger(value.bytes) || Number(value.bytes) < 0) { + throw new Error('campaign skill identity is invalid'); + } + return { ids: value.ids as string[], sha256: value.sha256, bytes: Number(value.bytes) }; +} + +function backendDoc(args: AgentArgs, p: StackRunPorts, track: Track): string { + const defaultGuidance = resolveDefaultGuidanceForStack(args.guidance, args.backend); + let defaultPath = defaultGuidance?.documents[args.backend]?.path; + if (!defaultPath && args.guidance === 'neutral') { + throw new Error(`neutral guidance has no document for ${args.backend}`); + } + defaultPath ??= join('backends', `${args.backend}.md`); + const raw = readBackendGuidanceDocument(args.guidanceDocument, defaultPath); + return raw + .replaceAll('', String(p.vite)) + .replaceAll('', String(p.express ?? '')) + .replaceAll('', track.title) + .replaceAll('', moduleName(track, args.runIndex)) + .replaceAll('', p.dbPort ? dbUrl(args.backend, args.runIndex, p.dbPort, track) ?? '' : '') + .replaceAll('', hostUrl(STDB_URI)) + .replaceAll('', C_BIN) + .replaceAll('', `file:${CODING_CONTAINER_SPACETIME_PACKAGE}`); +} + +// Fail before a paid session when the selected container cannot run this checkout. +function containerBlocker(backend: string): string | null { + try { + execFileSync('docker', ['image', 'inspect', IMAGE], + { stdio: 'pipe', timeout: CONTROL_COMMAND_TIMEOUT_MS }); + } catch (error: unknown) { + const detail = error instanceof Error ? error.message.split('\n')[0] : String(error).split('\n')[0]; + return `cannot verify isolation image ${IMAGE}: ${detail} — ` + + `build it with docker build -t ${IMAGE} ${fwd(join(ROOT, 'container'))}`; + } + if (!STACK_ADAPTER_REGISTRY.get(backend).agent.linuxCliRequired) return null; + if (!existsSync(LINUX_CLI)) { + return `no Linux SpacetimeDB CLI at ${fwd(LINUX_CLI)} — ` + + 'bash tools/stack-bench/container/build-linux-cli.sh'; + } + // A file at this path must be a Linux executable, not the Windows build. + const magic = Buffer.alloc(4); + try { + const fd = openSync(LINUX_CLI, 'r'); + try { readSync(fd, magic, 0, 4, 0); } finally { closeSync(fd); } + } catch { + return `cannot read the Linux SpacetimeDB CLI at ${fwd(LINUX_CLI)}`; + } + if (magic.toString('binary') !== '\x7fELF') { + return `${fwd(LINUX_CLI)} is not a Linux binary; rebuild it with ` + + 'container/build-linux-cli.sh'; + } + return null; +} + +function decideIsolation(args: AgentArgs): { container: true; reason: null } { + const blocker = containerBlocker(args.backend); + if (!blocker) return { container: true, reason: null }; + console.error(`agent.js: isolated build unavailable: ${blocker}`); + console.error(' benchmark coding sessions require the isolation container'); + process.exit(2); +} + +// Pin every round to the build's recorded container topology. +function resolveIsolation(args: AgentArgs): { container: true; reason: null } { + const marker = resolve(args.app, '..', '.stack-bench-isolation'); + const backendMarker = resolve(args.app, '..', '.stack-bench-backend'); + + if (args.mode === 'build') { + const decided = decideIsolation(args); + if (!args.printPrompt) { + mkdirSync(dirname(marker), { recursive: true }); + writeFileSync(marker, 'container'); + } + return decided; + } + + if (existsSync(marker)) { + const pinned = readFileSync(marker, 'utf8').trim(); + if (pinned !== 'container') { + console.error(`agent.js: unsupported isolation marker ${JSON.stringify(pinned)}; expected "container"`); + process.exit(2); + } + const blocker = containerBlocker(args.backend); + if (blocker) { + console.error(`agent.js: this run's build ran in a container, but ${blocker}`); + console.error(' refusing to run this round in a different environment'); + process.exit(2); + } + return { container: true, reason: null }; + } + + // A backend marker without an isolation marker is ambiguous prior state. + if (existsSync(backendMarker)) { + console.error('agent.js: app has prior benchmark state but no isolation marker'); + console.error(' refusing to guess where earlier rounds ran; start a clean run'); + process.exit(2); + } + const decided = decideIsolation(args); + if (!args.printPrompt) { + mkdirSync(dirname(marker), { recursive: true }); + writeFileSync(marker, 'container'); + } + return decided; +} + +export function buildPrompt(args: AgentArgs, p: StackRunPorts, track: Track, + materials: PromptMaterials = {}): string { + const prompt = (lines: string[]): string => assertAgentVisibleText(lines.join('\n')); + const applicationInterface = args.guidanceDocument?.applicationInterface + ?? resolveDefaultGuidanceForStack(args.guidance, args.backend) + ?.documents[args.backend]?.applicationInterface; + if (applicationInterface !== 'http' && applicationInterface !== 'reducer') { + throw new Error(`stack ${args.backend} has no application interface`); + } + const common = [ + `Build the app in ${CODING_CONTAINER_APP_ROOT}.`, + // Published container ports require the app to bind to all interfaces. + '', + 'The web application must listen on 0.0.0.0, not localhost, so it is reachable ' + + 'outside its process.', + 'The environment can run /app/start.sh again with APP_WARM_START=1. ' + + 'When dependencies are current, reuse them instead of installing them again.', + 'Startup must work with an empty database by creating the supplied starting data and accounts. ' + + 'On an existing database, preserve current quantities, prices, and user data. ' + + 'This applies after upgrades and repairs too.', + '', + 'Chromium is installed at /usr/bin/chromium (CHROME_BIN). ' + + 'Use that executable with --no-sandbox in this isolated container; no browser download is needed. ' + + 'Puppeteer Core is installed at /opt/browser-tools/node_modules/puppeteer-core. ' + + 'In a .cjs script, use const puppeteer = require("/opt/browser-tools/node_modules/puppeteer-core"); ' + + 'then await puppeteer.launch({ executablePath: process.env.CHROME_BIN, args: ["--no-sandbox"] }).', + '', + '## Stack', + '', + agentVisibleContractText(backendDoc(args, p, track), args.credentialAliases, + applicationInterface), + ]; + const skills = materials.skillsText ?? readAgentSkillDocuments(ROOT, args.skills ?? []); + if (skills) common.push('', '## Selected API reference', '', skills); + + if (args.mode === 'resume') { + return prompt([ + 'Restore the existing application to a runnable state.', + '', + 'This is a saved application from an earlier completed run. Install its', + 'dependencies and start its existing database module, server, and web client', + 'as needed. Do not implement features or fix application behavior. Do not', + 'change source files. The saved source must remain byte-for-byte identical.', + '', + 'Output RESUME_COMPLETE when the existing app is running.', + '', + ...common, + ]); + } + + if (args.productionQuality) common.unshift('Build a production-quality application suitable for real users, not a prototype or demo.', ''); + const startingCatalog = materials.startingCatalog + ? ['', '## Starting catalog', '', args.mode === 'build' + ? 'Use exactly this starting data:' + : 'This is the original catalog baseline. Preserve its entity names and relationships. Do not reset current quantities, prices, or user data.', + '', '```json', materials.startingCatalog, '```'] : []; + + if (args.mode === 'fix') { + return prompt([ + 'Fix the reported application bugs.', + '', + `Read ${CODING_CONTAINER_BUG_REPORT_FILE} in the app directory. Each entry says what was expected`, + 'and what actually happened. Fix the app so the behaviour matches, redeploy,', + 'and make sure the dev server is running.', + '', + 'Change only what is needed. Do not alter behaviour that is already correct.', + '', + 'Output FIX_COMPLETE when done.', + '', + ...common, + '', + agentVisibleContractText(materials.requirementText ?? levelPrompt(track, args.level), + args.credentialAliases, applicationInterface), + ...startingCatalog, + '', + '## Application interface', + '', + agentVisibleContractText(materials.contractText ?? appendix(track, args.level), + args.credentialAliases, applicationInterface), + ]); + } + + const verb = args.mode === 'upgrade' + ? [ + 'Add the features below to the existing app.', + '', + 'Keep completed features working. Add only the current features below.', + ] + : [`Build the application described below and leave it running.`]; + + return prompt([ + ...verb, + '', + `After the web application is running, reply with ${args.mode === 'upgrade' + ? 'UPGRADE_COMPLETE' : 'DEPLOY_COMPLETE'}.`, + '', + ...common, + '', + agentVisibleContractText(materials.requirementText ?? levelPrompt(track, args.level), + args.credentialAliases, applicationInterface), + ...startingCatalog, + '', + '## Application interface', + '', + agentVisibleContractText(materials.contractText ?? appendix(track, args.level), + args.credentialAliases, applicationInterface), + ]); +} + +export function agentScenarioPaths(track: Track, level: number, + recipeBinding: RecipeBinding | null = null): string[] { + const execution = recipeBinding?.execution; + if (execution) return execution.map(entry => resolve(track.dir, entry.source ?? '')); + return suitesFor(track, level).map(suite => suite.spec); +} + +export function agentRecipeRequest(explicitRecipe: string | null = null, + recipeTask: RecipeTaskRequest | null = null): RecipeRequest | null { + const bound = recipeTask?.recipe; + if (!bound) return explicitRecipe; + if (explicitRecipe && explicitRecipe !== bound.id) { + throw new Error(`agent recipe ${explicitRecipe} does not match bound task ${bound.id}`); + } + return bound; +} + +// The coding container must not contain the controller or grading inputs. + +export function refreshCodingInvocationCredentials({ provider, apiKey, keyFile, + expectedMode, env = process.env }: { provider: keyof typeof CODING_PROVIDERS; + apiKey?: string; keyFile?: string; expectedMode: string | null; env?: NodeJS.ProcessEnv }) { + const credential = keyFile ? readFileSync(keyFile, 'utf8').trim() + : apiKey ?? env[CODING_PROVIDERS[provider].apiKeyEnvironment] ?? ''; + if (keyFile && !credential) throw new Error('selected API key file is empty'); + const auth = resolveContainerAuth({ provider, apiKey: credential, env, + credentialsPath: CODING_PROVIDERS[provider].credentialPath }); + if (expectedMode !== null && expectedMode !== auth.mode) { + throw new Error('provider billing mode changed during the coding action'); + } + return { mode: auth.mode, env: { ...env, STACK_BENCH_AGENT_API_KEY: credential } }; +} + +async function main() { + const args = parseAgentArgs(process.argv); + const track = loadTrack(args.track); + const p = portsFor(track, args.backend, args.runIndex); + const adapter = STACK_ADAPTER_REGISTRY.get(args.backend); + const defaultGuidance = resolveDefaultGuidanceForStack(args.guidance, args.backend); + args.credentialAliases ??= defaultGuidance?.credentialAliases ?? {}; + const profileSkills = defaultGuidance?.skills[args.backend]?.ids; + const defaultSkills = profileSkills ?? [...adapter.agent.defaultSkills]; + const selectedSkills = selectAgentSkills(defaultSkills, + args.skillIdentity?.ids ?? args.skills ?? null); + const skillsText = readAgentSkillDocuments(ROOT, selectedSkills); + if (args.skillIdentity && (sha256(skillsText) !== args.skillIdentity.sha256 + || Buffer.byteLength(skillsText) !== args.skillIdentity.bytes)) { + throw new Error('campaign skill material changed after compilation'); + } + const recipeBinding = resolveRecipeRelease(track, args.level, + agentRecipeRequest(args.recipe ?? null, args.recipeTask ?? null)); + if (args.recipeTask && !recipeBinding) { + throw new Error(`L${args.level} has no recipe release for the requested task`); + } + const selectedTask = recipeBinding + ? (args.recipeTask + ? resolveBoundRecipeTaskRequest(recipeBinding, args.recipeTask) + : createBoundRecipeTaskRequest(recipeBinding)) + : null; + const requirementText = selectedTask?.task.requirementText ?? levelPrompt(track, args.level); + const contractText = selectedTask?.task.contractText ?? appendix(track, args.level); + const startingCatalog = recipeBinding ? JSON.stringify({ + warehouses: recipeBinding.plan.fixture.warehouses, + items: recipeBinding.plan.fixture.items, + }, null, 2) : undefined; + + // Print the exact prompt without starting a session or changing the app. + if (args.printPrompt) { + process.stdout.write(buildPrompt(args, p, track, + { skillsText, requirementText, contractText, startingCatalog })); + return; + } + if (args.mode === 'build') { + assertNewOrEmptyDirectory(args.app, 'build application directory'); + } + resolveIsolation(args); + const imageIdentity = resolveContainerImage(IMAGE); + // Build wipes all backend state. Later rounds preserve it. + ensureDatabase(args.backend, args.runIndex, p.dbPort, track, args.mode === 'build'); + // Never erase a caller-supplied application tree. + mkdirSync(args.app, { recursive: true }); + writeFileSync(resolve(args.app, '..', '.stack-bench-backend'), args.backend); + + const prompt = buildPrompt(args, p, track, + { skillsText, requirementText, contractText, startingCatalog }); + const bugReportPath = join(args.app, CODING_CONTAINER_BUG_REPORT_FILE); + const bugReportText = args.mode === 'fix' && existsSync(bugReportPath) + ? readFileSync(bugReportPath, 'utf8') : null; + const provenance = sessionProvenance({ prompt, skillsText, contractText, bugReportText, + scenarioPaths: agentScenarioPaths(track, args.level, recipeBinding), + trackDir: track.dir, trackManifestPath: join(track.dir, TRACK_MANIFEST_FILE) }); + const started = Date.now(); + const retryLimitRaw = process.env.STACK_BENCH_CODING_INTERRUPTION_RETRIES + ?? String(DEFAULT_CODING_INTERRUPTION_RETRIES); + const retryLimit = Number(retryLimitRaw); + if (!Number.isInteger(retryLimit) || retryLimit < 0 || retryLimit > 3) { + throw new Error('STACK_BENCH_CODING_INTERRUPTION_RETRIES must be an integer from 0 to 3'); + } + // The throttle wait must fit inside the adapter deadline. + const throttleWaitRaw = process.env.STACK_BENCH_PROVIDER_THROTTLE_MAX_WAIT_MINUTES + ?? String(DEFAULT_THROTTLE_MAX_WAIT_MS / 60_000); + const throttleMaxWaitMinutes = Number(throttleWaitRaw); + if (!Number.isInteger(throttleMaxWaitMinutes) || throttleMaxWaitMinutes < 0 + || throttleMaxWaitMinutes > DEFAULT_THROTTLE_MAX_WAIT_MS / 60_000) { + throw new Error('STACK_BENCH_PROVIDER_THROTTLE_MAX_WAIT_MINUTES must be an integer from 0 to ' + + `${DEFAULT_THROTTLE_MAX_WAIT_MS / 60_000}`); + } + // Concurrent campaign slots must not wake and retry as one burst. This + // stable offset keeps retries reproducible while spreading them over 45s. + const throttleJitterMs = parseInt(sha256(Buffer.from( + `${args.backend}:${args.runIndex}:${args.level}:${args.mode}`)).slice(0, 8), 16) % 45_001; + const selectedKeyFile = process.env.STACK_BENCH_AGENT_API_KEY_FILE + ?? process.env.STACK_BENCH_API_KEY_FILE + ?? process.env[`${CODING_PROVIDERS[args.provider].apiKeyEnvironment}_FILE`]; + let selectedAuthMode: string | null = null; + const invocationEnvironment = (baseEnv: NodeJS.ProcessEnv = process.env): NodeJS.ProcessEnv => { + const refreshed = refreshCodingInvocationCredentials({ provider: args.provider, apiKey: args.apiKey, + keyFile: selectedKeyFile, expectedMode: selectedAuthMode, env: baseEnv }); + selectedAuthMode = refreshed.mode; + return refreshed.env; + }; + const actionId = randomUUID(); + const continuationContext = campaignProviderContinuationContext(); + const continuationIdentity = { actionId, mode: args.mode, level: args.level, model: args.model, + provider: args.provider, providerRoute: args.providerRoute, imageId: imageIdentity.id, provenance, pricing: args.pricing, + maxOutputTokens: args.maxOutputTokens, + guidance: args.guidance, skillIdentity: args.skillIdentity, + ...(args.productionQuality ? { productionQuality: true } : {}), + continuationMessage: PROVIDER_CONTINUATION_MESSAGE }; + let coding: CodingSessionRetryResult; + try { + // Send prompts through stdin to avoid the Windows command-line limit. + const cliEnv = { ...process.env, + // Absent unless deliberately overridden — see THINKING_TOKENS above. + ...(args.provider === 'anthropic' && (args.thinking ?? THINKING_TOKENS) + ? { MAX_THINKING_TOKENS: String(args.thinking ?? THINKING_TOKENS) } + : {}), + // Keep the CLI fixed across the campaign. + ...(args.provider === 'anthropic' ? { DISABLE_AUTOUPDATER: '1', + // Pin cache lifetime so run order cannot change cost. + FORCE_PROMPT_CACHING_5M: '1' } : {}) }; + + coding = runCodingSessionWithRetries({ prompt, model: args.model, retryLimit, + maxBudgetUsd: args.maxBudgetUsd, + throttleMaxWaitMs: throttleMaxWaitMinutes * 60_000, + throttleJitterMs, + onInvocation: record => persistCampaignProviderInvocation({ + evidence: { ...continuationIdentity, ...record, billingMode: selectedAuthMode } }), + waitForProvider: continuationContext ? request => { + const nativeOptions = { appDir: args.app, provider: args.provider, + sessionId: request.sessionId, model: args.model, imageId: imageIdentity.id, env: process.env }; + const nativeIdentity = captureNativeContinuation(nativeOptions); + return waitForCampaignProviderContinuation({ + evidence: { ...continuationIdentity, ...request, nativeIdentity, billingMode: selectedAuthMode }, + validate: phase => { + const env = phase === 'continue' ? invocationEnvironment() : process.env; + if (captureNativeContinuation({ ...nativeOptions, env }) !== nativeIdentity) { + throw new Error('native provider session or runtime changed during provider wait'); + } + }, + }); + } : undefined, + invoke: ({ input, maxBudgetUsd, resumeSession, recoverStoppedContainer }) => + execFileSync(process.execPath, [ + compiledEntrypoint('container', 'run-build.js'), + '--provider', args.provider, + ...(args.providerRoute ? ['--provider-route', args.providerRoute] : []), + ...(args.maxOutputTokens ? ['--max-output-tokens', String(args.maxOutputTokens)] : []), + '--app', args.app, + '--backend', args.backend, + '--image', imageIdentity.id, + '--effort', EFFORT, + '--model', args.model, + ...(args.pricing ? ['--pricing-json', JSON.stringify(args.pricing)] : []), + '--completion-marker', args.mode === 'fix' ? 'FIX_COMPLETE' + : args.mode === 'upgrade' ? 'UPGRADE_COMPLETE' + : args.mode === 'resume' ? 'RESUME_COMPLETE' : 'DEPLOY_COMPLETE', + ...(maxBudgetUsd != null ? ['--max-budget-usd', String(maxBudgetUsd)] : []), + '--ports', [p.vite, p.express].filter(Boolean).join(','), + ...(resumeSession ? ['--resume-session', resumeSession] : []), + ...(recoverStoppedContainer ? ['--recover-stopped-container'] : []), + ], { input, encoding: 'utf8', maxBuffer: 256 * 1024 * 1024, + env: invocationEnvironment(cliEnv), + timeout: AGENT_PROCESS_TIMEOUT_MS }), + }); + } catch (err: unknown) { + coding = { raw: '', spawnError: codingSessionFailure(isRecord(err) ? err : {}), sessionResults: [], + interruptions: [], result: { total_cost_usd: 0, num_turns: 0, + usage: { input_tokens: 0, output_tokens: 0, cache_creation_input_tokens: 0, + cache_read_input_tokens: 0 }, stack_bench_cost_receipts: [] }, + throttle: { waits: 0, waitedMs: 0, maxWaitMs: throttleMaxWaitMinutes * 60_000, + jitterMs: throttleJitterMs } }; + } + + const { raw, spawnError, sessionResults, interruptions, result, throttle } = coding; + const noOutput = !result.session_id && !raw.trim(); + const failed = Boolean(spawnError || noOutput); + const providerFailure = providerSessionFailure(result); + const usage = sessionUsage(result.usage); + const input = usage.input_tokens ?? 0; + const output = usage.output_tokens ?? 0; + const cacheWrite = usage.cache_creation_input_tokens ?? 0; + const cacheRead = usage.cache_read_input_tokens ?? 0; + const turns = result.num_turns ?? 0; + + // Preserve the cost inputs needed to explain stack differences. + const setupMetadata = adapter.agent.setupMetadata({ + imageId: imageIdentity.id, + localPackage: LOCAL_PKG, + env: process.env, + helpers: { linuxSpacetimeVersion, bindingsIdentity, containerImage }, + }); + const out = { + ...(args.productionQuality ? { productionQuality: true } : {}), + appDir: args.app, + mode: args.mode, + level: args.level, + track: args.track, + backend: args.backend, + model: args.model, + guidance: args.guidance, + setup: { + provider: args.provider, + ...(args.providerRoute ? { providerRoute: args.providerRoute } : {}), + ...(args.maxOutputTokens ? { maxOutputTokens: args.maxOutputTokens } : {}), + thinkingTokens: args.provider !== 'anthropic' ? null : (args.thinking ?? THINKING_TOKENS) ? Number(args.thinking ?? THINKING_TOKENS) : 'cli default', + permissionMode: args.provider === 'anthropic' ? 'acceptEdits' : 'container-isolated', + effort: EFFORT, + skills: selectedSkills, + cacheTier: args.provider === 'anthropic' ? '5m' : 'provider-managed', + autoUpdater: 'disabled', + codingInterruptionRetries: { limit: retryLimit, + used: interruptions.filter(item => item.kind !== 'provider-throttled').length }, + providerThrottle: { maxWaitMinutes: throttleMaxWaitMinutes, + waits: throttle?.waits ?? 0, waitedMs: throttle?.waitedMs ?? 0, + jitterMs: throttle?.jitterMs ?? throttleJitterMs }, + cliVersion: imageCliVersion(imageIdentity.id, CODING_PROVIDERS[args.provider].executable), + isolation: { mode: 'container', image: imageIdentity.reference, + imageId: imageIdentity.id, hostAlias: HOST_ADDR }, + auth: selectedAuthMode ?? 'not-selected', + ...(isRecord(setupMetadata) ? setupMetadata : {}), + env: ambientEnv(), + node: { orchestrator: process.version, codingContainer: imageNodeVersion(imageIdentity.id) }, + platform: process.platform, + resources: result.stack_bench_resources ?? null, + }, + costUsd: Number((result.total_cost_usd ?? 0).toFixed(6)), + costReceipts: result.stack_bench_cost_receipts ?? [], + tokens: input + output + cacheWrite + cacheRead, + outputTokens: output, + usage: { input, output, cacheWrite, cacheRead }, + provenance, + turns, + promptBytes: Buffer.byteLength(prompt), + tokensPerTurn: turns ? Math.round((input + output + cacheWrite + cacheRead) / turns) : null, + thinking: args.provider === 'anthropic' + ? combinedThinkingVolume(args.app, sessionResults.map(item => item.session_id)) : null, + durationMs: Date.now() - started, + sessionId: result.session_id ?? null, + ok: !failed && result.is_error === false, + providerMetadata: { failureCode: failed + ? String(spawnError ?? '').startsWith('provider stayed throttled') + ? 'provider-throttle-exhausted' + : providerFailure?.code ?? (noOutput ? 'coding-session-no-output' : 'coding-session-failed') + : result.is_error === true ? 'provider-session-error' : null, + diagnostic: spawnError, + failure: failed ? { + providerStatus: result.api_error_status ?? null, + waitedMs: throttle?.waitedMs ?? 0, + waits: throttle?.waits ?? 0, + ...(result.stack_bench_provider_failure?.budget ? { budget: result.stack_bench_provider_failure.budget } : {}), + } : null, + interruptions, invocations: sessionResults.length, + providerWaits: coding.providerWaits ?? [], + terminalRecovery: isRecord(result) ? result.terminal_recovery ?? null : null, + credentialBroker: result.stack_bench_credential_broker ?? null, + sessionIds: [...new Set(sessionResults.map(item => item.session_id).filter(Boolean))], + models: args.provider === 'anthropic' + ? transcriptModels(args.app, sessionResults.map(item => item.session_id)) : [] }, + }; + console.log(JSON.stringify(out)); +} + +if (process.argv[1] && resolve(process.argv[1]) === fileURLToPath(import.meta.url)) { + main().catch(err => { console.error(err); process.exit(1); }); +} diff --git a/tools/stack-bench/commands/bench-arguments.ts b/tools/stack-bench/commands/bench-arguments.ts new file mode 100644 index 00000000000..d1e442a215e --- /dev/null +++ b/tools/stack-bench/commands/bench-arguments.ts @@ -0,0 +1,368 @@ +import { dirname, resolve } from 'node:path'; +import { parseArgs } from 'node:util'; +import { readArtifact } from '../src/evidence/artifacts.js'; +import { DEFAULT_TRACK, RUN_INDEX_CAP } from '../src/composition/tracks.js'; +import { campaignProgressionOwner, validateCompiledCampaignPlan } from '../src/campaigns/campaign-compiler.js'; +import type { CampaignAttemptPlan, CampaignSelection } + from '../src/campaigns/campaign-compiler.js'; +import { readCampaignAdmission } + from '../src/campaigns/campaign-admission.js'; +import { compileProgressionInput, dependencyRuntimeDefinition, progressionLevels, + validateFeatureCatalogInput, validateProgressionInput } + from '../src/progression/progression-definition.js'; +import type { CompiledDependencyPolicyDefinition, CompiledProgressionDefinition, + ProgressionInput } from '../src/progression/progression-definition.js'; +import { validatePricingAuthority } from '../src/evidence/pricing-authority.js'; +import type { PricingAuthority } from '../src/evidence/pricing-authority.js'; +import { parseGuidanceMode } from '../src/campaigns/condition-compiler.js'; +import type { GuidanceMode } from '../src/campaigns/condition-compiler.js'; +import { validateCampaignExtensionSeed } from '../src/campaigns/campaign-scheduler.js'; +import type { CampaignExtensionSeed } from '../src/campaigns/campaign-scheduler.js'; +import { repairBudgetLimit } from '../src/progression/repair-plan.js'; + +type StudyCondition = CampaignAttemptPlan['condition']; +type UnknownRecord = Record; + +export interface BenchArguments { + backend?: string; + track: string; + levels: string; + levelsProvided: boolean; + levelList: number[]; + model: string | null; + providerRoute?: string; + maxOutputTokens?: number; + agentAdapter: string; + pricing?: PricingAuthority | null; + repairs: number; + maxStalledRepairs: number; + maxBudgetUsd?: number; + runIndex: number; + out?: string; + app?: string; + url?: string; + media: boolean; + retainBackend?: boolean; + guidance: GuidanceMode; + productionQuality?: boolean; + guidanceDocument?: unknown; + condition?: StudyCondition; + /** Aliases the grader expects instead of the condition's; `{}` grades with the fixture credentials. */ + gradingCredentialAliases?: Record; + selectionRequest?: CampaignSelection; + taskMode?: string; + retainPriorContracts?: boolean; + pauseAfterDepth?: number; + packIds: string[]; + checkKeys: string[]; + featureIds: string[]; + requestedSpecifications: string[]; + expectedSpecifications: string[]; + observedSpecifications: string[]; + skills?: string[]; + apiKey?: string; + apiKeyFile?: string; + mutations?: string; + mutationShardIndex?: number; + mutationShardCount?: number; + mutationResumeFrom?: string; + mutationCheckpointOut?: string; + mutationBaselineBundle?: string; + expectedMutationCalibration?: unknown; + mutationMaxRuntimeMinutes: number; + referenceMutationOnly?: boolean; + seedFrom?: string; + seedThrough?: number; + progressionSeed?: CampaignExtensionSeed; + parentAttemptId?: string; + repairFrom?: string; + gradeFrom?: string; + gradeLevel?: number; + repairLevel?: number; + recipe?: string; + campaignFile?: string; + campaignAttemptId?: string; + campaignAdmissionId?: string; + progressionResumeFrom?: string; + experimentIdentity?: { id: string; version: string; sha256: string; state: string }; + runMode?: CampaignAttemptPlan['mode']; + featureCatalog?: ProgressionInput; + dependencyPolicy?: ProgressionInput; + progression?: ProgressionInput; + progressionOwner?: UnknownRecord; +} + +interface BenchCliOptions extends Partial { + pack?: string[]; + check?: string[]; + pricingJson?: unknown; + featureModule?: string[]; + requestSpec?: string[]; + expectSpec?: string[]; + observeSpec?: string[]; + expectedMutationCalibrationJson?: unknown; + progressionSeedJson?: unknown; +} + +function parseCli(argv: readonly string[]): BenchCliOptions { + const strings = ['backend', 'track', 'levels', 'campaign-file', 'campaign-attempt-id', + 'campaign-admission-id', 'progression-resume-from', 'recipe', 'model', 'provider-route', 'max-output-tokens', 'pricing-json', + 'repairs', 'max-stalled-repairs', 'max-budget-usd', 'run-index', 'out', 'app', 'url', + 'agent-adapter', 'guidance', 'task-mode', 'skills', 'mutations', + 'mutation-shard-index', 'mutation-shard-count', 'mutation-resume-from', + 'mutation-checkpoint-out', 'mutation-baseline-bundle', + 'expected-mutation-calibration-json', 'mutation-max-runtime-minutes', 'seed-from', + 'seed-through', 'progression-seed-json', + 'parent-attempt-id', 'repair-from', 'repair-level', 'grade-from', 'grade-level'] as const; + const multiple = ['pack', 'check', 'feature-module', 'request-spec', 'expect-spec', + 'observe-spec'] as const; + const options = Object.fromEntries([ + ...strings.map(name => [name, { type: 'string' as const }]), + ...multiple.map(name => [name, { type: 'string' as const, multiple: true }]), + ...['no-media', 'retain-backend', 'reference-mutation-only', 'production-quality', 'no-production-quality'].map(name => + [name, { type: 'boolean' as const }]), + ]); + const { values } = parseArgs({ args: [...argv.slice(2)], options, strict: true, + allowPositionals: false }); + const parsed: Record = {}; + for (const [key, value] of Object.entries(values)) { + parsed[key.replace(/-([a-z])/g, (_, letter: string) => letter.toUpperCase())] = value; + } + for (const key of ['pack', 'check', 'featureModule', 'requestSpec', 'expectSpec', + 'observeSpec']) { + const value = parsed[key] as string[] | undefined; + if (value) parsed[key] = value.flatMap(item => item.split(',').filter(Boolean)); + } + for (const key of ['repairs', 'maxStalledRepairs', 'maxBudgetUsd', 'maxOutputTokens', 'mutationShardIndex', + 'mutationShardCount', 'mutationMaxRuntimeMinutes', 'repairLevel', 'gradeLevel', 'seedThrough']) { + if (typeof parsed[key] === 'string') parsed[key] = Number(parsed[key]); + } + if (typeof parsed.runIndex === 'string') parsed.runIndex = Number(parsed.runIndex); + for (const key of ['campaignFile', 'progressionResumeFrom', 'mutations', + 'mutationResumeFrom', 'mutationCheckpointOut', 'mutationBaselineBundle', 'repairFrom', 'gradeFrom']) { + if (typeof parsed[key] === 'string') parsed[key] = resolve(parsed[key]); + } + for (const key of ['pricingJson', 'expectedMutationCalibrationJson', 'progressionSeedJson']) { + if (typeof parsed[key] === 'string') parsed[key] = JSON.parse(parsed[key]); + } + if (typeof parsed.guidance === 'string') parsed.guidance = parseGuidanceMode(parsed.guidance); + if (typeof parsed.skills === 'string') parsed.skills = parsed.skills.split(',').filter(Boolean); + if (parsed.noMedia === true) parsed.media = false; + delete parsed.noMedia; + if (parsed.productionQuality && parsed.noProductionQuality) throw new Error('choose only one production-quality flag'); + if (parsed.noProductionQuality) parsed.productionQuality = false; + delete parsed.noProductionQuality; + return parsed as BenchCliOptions; +} + +export function parseBenchArguments(argv: readonly string[]): BenchArguments { + const args: BenchArguments = { model: null, agentAdapter: 'claude-code', + repairs: 10, runIndex: 0, levels: '1', levelsProvided: false, media: true, + levelList: [], maxStalledRepairs: 3, guidance: 'prescribed', productionQuality: true, track: DEFAULT_TRACK, + packIds: [], checkKeys: [], featureIds: [], requestedSpecifications: [], + expectedSpecifications: [], observedSpecifications: [], + mutationMaxRuntimeMinutes: 60 }; + const { pack, check, pricingJson, featureModule, requestSpec, expectSpec, observeSpec, + expectedMutationCalibrationJson, progressionSeedJson, ...options } = parseCli(argv); + Object.assign(args, options); + if (args.gradeLevel !== undefined && (!args.gradeFrom + || !Number.isSafeInteger(args.gradeLevel) || args.gradeLevel < 1)) { + throw new Error('--grade-level requires --grade-from and a positive integer depth'); + } + for (const flag of ['--grade-from', '--grade-level']) { + if (argv.slice(2).filter(value => value.split('=', 1)[0] === flag).length > 1) { + throw new Error(`${flag} must be supplied only once`); + } + } + if (args.gradeFrom) { + const allowed = new Set(['--grade-from', '--grade-level', '--out', '--no-media', '--check']); + const forbidden = argv.slice(2).find(value => value.startsWith('--') + && !allowed.has(value.split('=', 1)[0]!)); + if (forbidden) throw new Error(`--grade-from cannot be combined with ${forbidden}`); + if (!args.out) throw new Error('--grade-from requires a separate --out directory'); + args.out = resolve(args.out); + args.repairs = 0; + } + if (pack) args.packIds = pack; + if (check) args.checkKeys = check; + if (pricingJson !== undefined) { + args.pricing = validatePricingAuthority(pricingJson, { at: '--pricing-json' }); + } + if (featureModule) args.featureIds = featureModule; + if (requestSpec) args.requestedSpecifications = requestSpec; + if (expectSpec) args.expectedSpecifications = expectSpec; + if (observeSpec) args.observedSpecifications = observeSpec; + args.levelsProvided = options.levels !== undefined; + if (expectedMutationCalibrationJson !== undefined) { + args.expectedMutationCalibration = expectedMutationCalibrationJson; + } + if (progressionSeedJson !== undefined) { + args.progressionSeed = validateCampaignExtensionSeed(progressionSeedJson); + } + if ((args.mutationResumeFrom || args.mutationCheckpointOut || args.mutationBaselineBundle) + && !args.mutations) { + throw new Error('mutation control options require --mutations'); + } + if (args.expectedMutationCalibration && !args.mutations) { + throw new Error('--expected-mutation-calibration-json requires --mutations'); + } + if (!Number.isFinite(args.mutationMaxRuntimeMinutes) || args.mutationMaxRuntimeMinutes < 1 + || args.mutationMaxRuntimeMinutes > 120) { + throw new Error('--mutation-max-runtime-minutes must be from 1 through 120'); + } + if (args.referenceMutationOnly && (!args.mutations || args.agentAdapter !== 'reference-fixture' + || args.repairs !== 0 || !args.app || args.campaignFile)) { + throw new Error('--reference-mutation-only requires a mutation-bound reference fixture run'); + } + if (args.mutationBaselineBundle && !args.referenceMutationOnly) { + throw new Error('--mutation-baseline-bundle is an internal reference mutation option'); + } + if (args.repairFrom && (args.repairLevel === undefined + || !Number.isSafeInteger(args.repairLevel) || args.repairLevel < 1)) { + throw new Error('--repair-from requires --repair-level with a positive integer'); + } + if (args.campaignFile && !args.campaignAttemptId) { + throw new Error('--campaign-file requires --campaign-attempt-id'); + } + if (!args.campaignFile && (args.campaignAttemptId || args.campaignAdmissionId)) { + throw new Error('campaign binding requires --campaign-file'); + } + if (args.progressionResumeFrom && !args.campaignFile) { + throw new Error('--progression-resume-from requires a compiled campaign'); + } + if (args.seedThrough !== undefined && (!args.seedFrom || !args.campaignFile)) { + throw new Error('--seed-through requires --seed-from and a compiled campaign'); + } + if (args.seedThrough !== undefined && !args.progressionSeed) { + throw new Error('--seed-through requires --progression-seed-json'); + } + if (args.progressionSeed !== undefined && args.seedThrough === undefined) { + throw new Error('--progression-seed-json requires --seed-through'); + } + if (args.progressionSeed && args.progressionSeed.fromDepth !== args.seedThrough) { + throw new Error('--progression-seed-json does not match --seed-through'); + } + if (args.campaignFile) { + const allowed = new Set(['--campaign-file', '--campaign-attempt-id', + '--campaign-admission-id', '--progression-resume-from', '--run-index', '--out', + '--max-budget-usd', '--seed-from', '--seed-through', '--progression-seed-json']); + const override = argv.slice(2).find(value => value.startsWith('--') + && !allowed.has(value.split('=', 1)[0]!)); + if (override) throw new Error(`campaign attempts cannot override ${override}`); + bindCampaign(args); + } + if (!args.backend && !args.repairFrom && !args.gradeFrom) { + throw new Error('--backend is required unless --repair-from, --grade-from, or --campaign-file is supplied'); + } + if (args.progression) { + if (args.levelsProvided) throw new Error('--levels cannot be combined with progression input'); + args.progression = validateProgressionInput(args.progression); + args.levelList = progressionLevels(args.progression); + args.levels = `${args.levelList[0]}-${args.levelList.at(-1)}`; + const seedThrough = args.seedThrough; + if (seedThrough !== undefined && (!args.levelList.includes(seedThrough) + || !args.levelList.some(level => level > seedThrough))) { + throw new Error('--seed-through must precede another planned dependency depth'); + } + if (seedThrough !== undefined + && args.dependencyPolicy?.definition.workSelection !== 'progressive') { + throw new Error('--seed-through requires progressive dependency work selection'); + } + } else { + const [fromText, toText] = args.levels.split('-'); + const from = Number(fromText); + const to = toText === undefined ? from : Number(toText); + if (!Number.isSafeInteger(from) || from < 1 || !Number.isSafeInteger(to) || to < from) { + throw new Error('--levels must be one positive level or an ascending range'); + } + args.levelList = Array.from({ length: (to ?? from) - from + 1 }, (_, index) => from + index); + if (args.seedThrough !== undefined) { + throw new Error('--seed-through requires dependency mode'); + } + } + if (args.recipe && args.levelList.length !== 1) { + throw new Error('--recipe requires exactly one requested level'); + } + if (!Number.isSafeInteger(args.repairs) || args.repairs < 0) { + throw new Error('--repairs must be a non-negative safe integer'); + } + if (!Number.isInteger(args.maxStalledRepairs) || args.maxStalledRepairs < 0 + || args.maxStalledRepairs > 20) { + throw new Error('--max-stalled-repairs must be an integer from 0 through 20'); + } + if (args.maxBudgetUsd !== undefined + && (!Number.isFinite(args.maxBudgetUsd) || args.maxBudgetUsd <= 0)) { + throw new Error('--max-budget-usd must be a positive number'); + } + if (!Number.isSafeInteger(args.runIndex) || args.runIndex < 0 || args.runIndex > RUN_INDEX_CAP) { + throw new Error(`--run-index must be an integer from 0 through ${RUN_INDEX_CAP}`); + } + if ((args.mutationShardIndex === undefined) !== (args.mutationShardCount === undefined)) { + throw new Error('--mutation-shard-index and --mutation-shard-count must be supplied together'); + } + return args; +} + +function bindCampaign(args: BenchArguments): void { + if (!args.campaignFile) throw new Error('campaign file is required'); + const artifact = readArtifact(args.campaignFile, { expectedKind: 'campaign_plan' }); + const plan = validateCompiledCampaignPlan(artifact.payload); + const attempt = plan.attempts.find(item => item.id === args.campaignAttemptId); + if (!attempt) throw new Error('--campaign-attempt-id is not in the compiled campaign plan'); + const plannedBudget = plan.definition.budgets.maxCostUsdPerAttempt; + if (args.maxBudgetUsd !== undefined + && (plannedBudget === null || args.maxBudgetUsd > plannedBudget)) { + throw new Error('--max-budget-usd exceeds the compiled campaign budget'); + } + args.backend = attempt.stack; + args.track = plan.definition.track; + args.model = attempt.model; + if (args.providerRoute !== undefined && args.providerRoute !== attempt.providerRoute) { + throw new Error('--provider-route differs from the compiled campaign'); + } + args.providerRoute = attempt.providerRoute; + if (args.maxOutputTokens !== undefined && args.maxOutputTokens !== attempt.maxOutputTokens) { + throw new Error('--max-output-tokens differs from the compiled campaign'); + } + args.maxOutputTokens = attempt.maxOutputTokens; + args.agentAdapter = attempt.agentAdapter; + args.pricing = validatePricingAuthority(attempt.pricing, { at: 'compiled campaign pricing' }); + args.guidance = parseGuidanceMode(attempt.guidance); + args.condition = structuredClone(attempt.condition); + args.productionQuality = attempt.condition.productionQuality === true; + args.skills = structuredClone(attempt.skills); + args.selectionRequest = structuredClone(plan.definition.selection); + args.guidanceDocument = structuredClone( + attempt.condition.guidance.documents[attempt.stack]); + args.packIds = structuredClone(plan.definition.selection.packs ?? []); + args.checkKeys = structuredClone(plan.definition.selection.checks ?? []); + args.repairs = attempt.mode.id === 'dependency' + ? 0 : repairBudgetLimit(plan.definition.repair); + args.maxBudgetUsd ??= plannedBudget ?? undefined; + args.parentAttemptId = attempt.id; + args.media = false; + args.levels = `${Math.min(...attempt.levels)}-${Math.max(...attempt.levels)}`; + args.experimentIdentity = { + id: plan.id, version: plan.version, sha256: plan.contentSha256, state: plan.state, + }; + if (args.campaignAdmissionId) { + const admission = readCampaignAdmission(dirname(args.campaignFile), + args.campaignAdmissionId, plan); + if (!admission.ok) throw new Error('campaign admission did not pass'); + } + args.runMode = structuredClone(attempt.mode); + if (plan.featureCatalog) { + args.featureCatalog = validateFeatureCatalogInput(plan.featureCatalog); + } + if (attempt.mode.id === 'dependency') { + args.pauseAfterDepth = attempt.mode.pauseAfterDepth; + args.retainPriorContracts = attempt.mode.retainPriorContracts === true; + if (!plan.dependencyPolicy || !args.featureCatalog) { + throw new Error('dependency campaign requires a feature catalog and dependency policy'); + } + args.dependencyPolicy = plan.dependencyPolicy; + args.progression = compileProgressionInput(dependencyRuntimeDefinition( + args.featureCatalog, args.dependencyPolicy)); + args.progressionOwner = { ...campaignProgressionOwner(plan, attempt) }; + } +} diff --git a/tools/stack-bench/commands/bench.ts b/tools/stack-bench/commands/bench.ts new file mode 100644 index 00000000000..52686a64f67 --- /dev/null +++ b/tools/stack-bench/commands/bench.ts @@ -0,0 +1,3166 @@ +#!/usr/bin/env node + +import { campaignProviderContinuationContext } from '../src/campaigns/campaign-provider-continuation.js'; +import { execFileSync } from 'node:child_process'; +import type { ExecFileSyncOptionsWithStringEncoding } from 'node:child_process'; +import { readFileSync, writeFileSync, mkdirSync, mkdtempSync, existsSync, copyFileSync, cpSync, rmSync, readdirSync, realpathSync, lstatSync } from 'node:fs'; +import { join, dirname, resolve, relative, sep, isAbsolute } from 'node:path'; +import { tmpdir } from 'node:os'; +import { pathToFileURL } from 'node:url'; +import { loadTrack, resultsName, portsFor, workDirFor, + moduleName, dbName, suitesFor } from '../src/composition/tracks.js'; +import { parseBenchArguments } from './bench-arguments.js'; +import type { BenchArguments } from './bench-arguments.js'; +import { packageRegistry, packageRegistryEnvironment } from '../src/runtime/package-registry.js'; +import { runBounded } from '../src/runtime/bounded-process.js'; +import { formatRepairProgress } from '../src/evidence/scoring.js'; +import { ARTIFACT_FILE, emptyArtifactIdentities, readArtifact, readArtifactPayload, + writeArtifact, writeRunJson, currentEngineIdentity } from '../src/evidence/artifacts.js'; +import { aggregateRunOutcome, classifyBundle, ladderMayAdvance, ladderMayContinue, + mutationControlEligible, runExitCode, runOutcomeKind } from '../src/evidence/outcomes.js'; +import { summarizeSessions } from '../src/evidence/session-metrics.js'; +import { hashDirectory, sha256 } from '../src/evidence/provenance.js'; +import { createBackendLease, newRunId, publicBackendLease, readBackendLease, + claimBackendResourcesWhenAvailable, backendResourceLockKeys, resourceLockScope, loopbackHttpUri } from '../src/runtime/backend-lease.js'; +import { borrowCampaignReservation } + from '../src/campaigns/campaign-admission.js'; +import { captureApplicationDiagnostics } from '../src/runtime/backend-control.js'; +import type { RuntimeControlSpec } from '../src/runtime/backend-control.js'; +import { releaseBackendLease } from '../src/runtime/backend-teardown.js'; +import { resolveRecipeRelease } from '../src/composition/recipe-release.js'; +import { createAgentVisibleTaskRequest, createBoundRecipeTaskRequest } + from '../src/composition/recipe-selection.js'; +import { criterionEvidence, evidencePassed } from '../src/evidence/check-evidence.js'; +import { leasedDatabaseEnvironment, STACK_ADAPTER_REGISTRY } from '../src/stacks/stack-adapters.js'; +import { agentRecipeIdentity, agentRequestArgv, validateProviderRoute, validateProviderOutputLimit } from '../src/agents/agent-adapter-contract.js'; +import { agentSessionFailure, validateAgentResult } + from '../src/agents/agent-result-contract.js'; +import { AGENT_ADAPTER_REGISTRY, agentAdapterIdentity } from '../src/agents/agent-adapters.js'; +import { archiveTranscripts } from '../src/agents/transcript-archive.js'; +import { runPreflight } from '../src/runtime/preflight.js'; +import { checkpointSchema, recordRunCheckpoint } from '../src/evidence/run-checkpoints.js'; +import type { RunCheckpoint } from '../src/evidence/run-checkpoints.js'; +import { runCostEvidence } from '../src/evidence/cost-proof.js'; +import { redactCredentials } from '../src/evidence/diagnostic-sanitizer.js'; +import { DEFAULT_BUILD_IMAGE } from '../src/composition/product-config.js'; +import { SUPERVISOR_STATE_VERSION, writeRecoveryArtifact } from '../src/runtime/recovery.js'; +import { applyAgentCredential } from '../src/agents/agent-credentials.js'; +import { assertPlainAppSourceTree, hashAppSource, resetAppToSource, seedAppSource, snapshotAppSource } from '../src/runtime/source-snapshot.js'; +import { finalPackageEvidenceRequired, preserveFinalPackageEvidence, preserveLevelCheckpoint, + sourceBoundFirstBuildOutcome } from '../src/runtime/source-checkpoint.js'; +import { materializationAppFailure, materializeAcceptedSource, restoreRepairSource } + from '../src/runtime/source-materialization.js'; +import { compareRepairBaseline, createRepairGrant } from '../src/runtime/repair-grant.js'; +import { canonicalDefinitionJson } from '../src/composition/definition-plan.js'; +import { contractInterfaceNames } from '../src/composition/agent-visible-contract.js'; +import { clearPrivateGradingEvidence, privateGradingDirectory, levelGradeIsUsable, repairEvidenceDecision, + repairHistoryEntry, repairProgressState, repairRegressionDecision, + restorePrivateGradingEvidence } + from '../src/evidence/repair-evidence.js'; +import { mutationControlArgv, mutationControlTimeoutMs, pristineMutationBaselinePath } + from '../src/evidence/mutation-control.js'; +import type { MutationControlArgs } from '../src/evidence/mutation-control.js'; +import { progressionEngine } from '../src/progression/progression-engine.js'; +import { dependencyLevelRepairRecords, dependencyRepairBudget, dependencyRepairRecords, dependencyRepairStopReason } + from '../src/progression/dependency-mode.js'; +import { resolveProgressionRecipeAction, resolveProgressionRecipeLevelSelection, + resolveProgressionRepairTarget, validateProgressionCampaignLevelScope } + from '../src/progression/progression-recipe-selection.js'; +import { createLiveProgressionExecution, clearTimeContinuationBoundary, + commitTimeContinuationBoundary } + from '../src/progression/live-progression.js'; +import type { CampaignSelection } from '../src/campaigns/campaign-compiler.js'; +import { gradingRunTimeoutMs, selectedGradingSourceCount } + from '../src/runtime/grading-timeout.js'; +import { claudeRatesForModel } from '../src/evidence/claude-usage-cost.js'; +import { PRICING_UNIT, validatePricingAuthority } + from '../src/evidence/pricing-authority.js'; +import type { BoundRecipeTaskRequestResult } from '../src/composition/recipe-selection.js'; +import type { RecipeBinding } from '../src/composition/recipe-release.js'; +import type { RepairGrantResolution, RepairOutcome } from '../src/runtime/repair-grant.js'; +import type { AgentAdapter, AgentMode, AgentRequest } + from '../src/agents/agent-adapter-contract.js'; +import type { ValidatedAgentResult } from '../src/agents/agent-result-contract.js'; +import type { Track } from '../src/composition/tracks.js'; +import type { RunOutcome } from '../src/evidence/outcomes.js'; +import type { GradeBundlePayload, BenchmarkRunRecord, RunLevelRecord, + RunContinuation, RunRepairCandidate, RunSessionRecord, RunTotals } + from '../src/evidence/benchmark-run.js'; +import { readDepthPauseContext, waitAtDepthBoundary } from '../src/campaigns/campaign-depth-pause.js'; +import { addCostUsd, finalizeRunTotals, runSessionRecord } + from '../src/evidence/benchmark-run.js'; +import { formatLevelSummary } from '../src/evidence/evidence-presentation.js'; +import type { ProgressionAction } from '../src/progression/progression-engine.js'; +import type { ProgressionRepairRegression, ProgressionState } + from '../src/progression/progression-state.js'; +import type { ProgressionRecipeAction, ProgressionRecipeSelections } + from '../src/progression/progression-recipe-selection.js'; +import type { BackendLease } from '../src/runtime/backend-lease.js'; + +import { STACK_BENCH_ROOT as ROOT, compiledEntrypoint } from '../src/package-root.js'; +import { stackBenchResultsRoot } from '../src/runtime/operational-paths.js'; +import { runningContainerIdentity } from '../src/runtime/container-identity.js'; +const COMMAND_TIMEOUT_MS = 20 * 60_000; + +type UnknownRecord = Record; +type ContaminationAudit = { kind: 'contaminated' | 'harness_failure'; evidence: string[]; + verdict: string }; +type LeakAuditEntry = { hits: Array<{ kind: string; path: string }> }; +type CommandFailure = Error & { stdout?: string | Buffer; stderr?: string | Buffer; + status?: number | null; signal?: NodeJS.Signals | null }; +type GradeOptions = { observation?: 'scored' | 'observed'; out?: string | null; + sourceSha256?: string | null; applicationFailure?: RunOutcome | null; + recipeTask?: GradeRecipeTask }; +type MutationControlResult = UnknownRecord & { ok: boolean; artifact?: string; + skipped?: boolean; processError?: string | null; outcome: RunOutcome | null }; +type RecipeTask = (BoundRecipeTaskRequestResult | ProgressionRecipeSelections['grader']) & { agentRequest?: UnknownRecord; + progressionAction?: ProgressionAction }; +type BenchArgs = BenchArguments & { + recipeTasks: Map; + recipeBindings: Map; + repairGrant?: RepairGrantResolution; + mutationImageId?: string; + spentBudgetUsd?: number; +}; +type ProgressionWorkRecipeAction = ProgressionRecipeSelections & { + action: Exclude; +}; +type FirstBuildRecord = { + score: number | null; + max: number | null; + regression: NonNullable['regression'] | null; + contractPass: boolean | null; + outcome: RunOutcome; + source: { sha256: string; files: number } | null; + missed: string[]; + observations?: UnknownRecord; +}; +type RepairStatus = 'not-needed' | 'corrected' | 'budget-exhausted' | 'incomplete' | 'ungraded'; +type ProgressionFailure = { kind?: string; reason?: string }; + +const object = (value: unknown): value is UnknownRecord => + value !== null && typeof value === 'object' && !Array.isArray(value); + +const errorMessage = (error: unknown): string => + redactCredentials(error instanceof Error ? error.message : String(error)); + +function commandFailure(error: unknown): CommandFailure { + if (error instanceof Error) return error; + throw error; +} + +function parseLeakAudit(value: string): LeakAuditEntry[] { + const parsed: unknown = JSON.parse(value); + if (!Array.isArray(parsed)) throw new Error('contamination audit output must be an array'); + return parsed.map((entry, index) => { + if (!object(entry) || !Array.isArray(entry.hits)) { + throw new Error(`contamination audit output[${index}] is invalid`); + } + const hits = entry.hits.map((hit, hitIndex) => { + if (!object(hit) || typeof hit.kind !== 'string' || typeof hit.path !== 'string') { + throw new Error(`contamination audit output[${index}].hits[${hitIndex}] is invalid`); + } + return { kind: hit.kind, path: hit.path }; + }); + return { hits }; + }); +} + +function stringArray(value: unknown, at: string): string[] { + if (!Array.isArray(value) || value.some(entry => typeof entry !== 'string')) { + throw new Error(`${at} must be an array of strings`); + } + return [...value]; +} + +function campaignSelection(value: unknown, at: string): CampaignSelection { + if (!object(value)) throw new Error(`${at} must be an object`); + const optionalStrings = (field: 'packs' | 'checks'): string[] | undefined => { + const entry = value[field]; + if (entry === undefined) return undefined; + return stringArray(entry, `${at}.${field}`); + }; + let levels: CampaignSelection['levels']; + if (value.levels !== undefined) { + if (!Array.isArray(value.levels)) throw new Error(`${at}.levels must be an array`); + levels = value.levels.map((entry, index) => { + if (!object(entry)) throw new Error(`${at}.levels[${index}] is invalid`); + const level = entry.level; + const recipe = entry.recipe; + if (typeof level !== 'number' || !Number.isSafeInteger(level) || typeof recipe !== 'string') { + throw new Error(`${at}.levels[${index}] is invalid`); + } + return { level, recipe, + ...(entry.features === undefined ? {} : { features: stringArray(entry.features, + `${at}.levels[${index}].features`) }), + ...(entry.checks === undefined ? {} : { checks: stringArray(entry.checks, + `${at}.levels[${index}].checks`) }) }; + }); + } + return { ...(optionalStrings('packs') === undefined ? {} : { packs: optionalStrings('packs') }), + ...(optionalStrings('checks') === undefined ? {} : { checks: optionalStrings('checks') }), + ...(levels === undefined ? {} : { levels }) }; +} + +function isProgressionWorkRecipeAction(value: ProgressionRecipeAction): + value is ProgressionWorkRecipeAction { + return value.action.type !== 'terminal'; +} + +function repairCheckKeys(value: ProgressionRecipeAction | null): string[] { + if (!value || !isProgressionWorkRecipeAction(value) || value.action.type !== 'repair') return []; + if (!object(value.action.prompt) || !Array.isArray(value.action.prompt.nodeIds) + || !object(value.action.grading) || !Array.isArray(value.action.grading.checks)) { + throw new Error('dependency repair action has invalid prompt or grading selections'); + } + const promptNodeIds = new Set(value.action.prompt.nodeIds.map(nodeId => { + if (typeof nodeId !== 'string' || !nodeId) { + throw new Error('dependency repair action has an invalid prompt node'); + } + return nodeId; + })); + const checks = value.action.grading.checks.flatMap(check => { + if (!object(check) || typeof check.id !== 'string' || !check.id + || typeof check.nodeId !== 'string' || !check.nodeId) { + throw new Error('dependency repair action has an invalid grading check'); + } + return promptNodeIds.has(check.nodeId) ? [check.id] : []; + }); + if (checks.length === 0) throw new Error('dependency repair action selects no repair checks'); + return checks; +} + +function repairReportArgs(value: ProgressionRecipeAction | null): string[] { + const checks = repairCheckKeys(value); + if (!value || !isProgressionWorkRecipeAction(value) || checks.length === 0) return []; + const interfaces = contractInterfaceNames(value.agent.task.contractText); + return ['--checks-json', JSON.stringify(checks), + '--controls-json', JSON.stringify(interfaces)]; +} + +function repairOwnerNodeIds(value: ProgressionRecipeAction | null): string[] { + if (!value || !isProgressionWorkRecipeAction(value) || value.action.type !== 'repair') return []; + return [...value.action.repair.nodeIds].sort(); +} + +function savedRepairRegression(state: ProgressionState | null, + selected: ProgressionRecipeAction | null): ProgressionRepairRegression | null { + const saved = state?.attempts.at(-1)?.repairRegression; + if (!saved) return null; + const owners = repairOwnerNodeIds(selected); + return JSON.stringify([...saved.ownerNodeIds].sort()) === JSON.stringify(owners) + ? structuredClone(saved) : null; +} + +function requireProgressionState(state: ProgressionState | null): ProgressionState { + if (!state) throw new Error('live dependency progression has no active state'); + return state; +} + +function requireContinuation(run: BenchmarkRunRecord): RunContinuation { + if (!run.continuation) throw new Error('repair continuation has no continuation record'); + return run.continuation; +} + +function requireRunTotals(run: BenchmarkRunRecord): RunTotals { + if (!run.totals) throw new Error('benchmark run totals are not available'); + return run.totals; +} + +function repairOutcome(outcome: RunOutcome): RepairOutcome { + return { kind: outcome.kind, appFailures: [...(outcome.appFailures ?? [])], + inconclusive: [...(outcome.inconclusive ?? [])], + harnessFailures: [...(outcome.harnessFailures ?? [])] }; +} + +function progressionFailure(outcome: RunOutcome): ProgressionFailure { + return { kind: outcome.kind, ...(outcome.reason === null || outcome.reason === undefined + ? {} : { reason: outcome.reason }) }; +} + +function featureCheckKeys(selected: ProgressionWorkRecipeAction, + state: ProgressionState): string[] { + if (!object(selected.action.prompt) || !Array.isArray(selected.action.prompt.nodeIds)) { + throw new Error('feature action has no prompt nodes'); + } + const selectedNodes = new Set(selected.action.prompt.nodeIds); + return state.definition.nodes + .filter(node => selectedNodes.has(node.id)) + .flatMap(node => node.gradingChecks + .filter(check => check.role === 'feature') + .map(check => check.id)); +} + +function bundlePassedChecks(bundle: GradeBundlePayload | null): Set { + return new Set(Object.values(bundle?.suites ?? {}).flatMap(suite => + (suite?.features ?? []).flatMap(feature => + (feature.criteria ?? []).flatMap(criterion => + typeof criterion.stableKey === 'string' + && evidencePassed(criterionEvidence(criterion)) ? [criterion.stableKey] : [])))); +} + +function featureCandidateAccepted(selected: ProgressionWorkRecipeAction, + state: ProgressionState, candidate: GradeBundlePayload | null): boolean { + if (!levelGradeIsUsable(classifyBundle(candidate))) return false; + const passed = bundlePassedChecks(candidate); + if (!featureCheckKeys(selected, state).every(check => passed.has(check))) return false; + return state.definition.nodes.every(node => node.gradingChecks.every(check => + state.nodes[node.id]?.checks[check.id] !== 'pass' || passed.has(check.id))); +} + +function featureActionNeedsCoding(selected: ProgressionWorkRecipeAction, + state: ProgressionState): boolean { + if (selected.action.type === 'repair') return true; + if (!object(selected.action.prompt) || !Array.isArray(selected.action.prompt.nodeIds)) { + throw new Error('feature action has no prompt nodes'); + } + return selected.action.prompt.nodeIds.some(nodeId => { + const node = state.nodes[String(nodeId)]; + return node?.status === 'active' + && Object.values(node.checks).every(outcome => outcome === null); + }); +} + +export function synchronizeProgressionSummary(run: Pick, + state: ProgressionState): void { + run.validation.ladder.completedLevels = [...new Set(state.attempts + .filter(attempt => attempt.outcome === 'conclusive').map(attempt => attempt.level))]; + for (const level of run.levels) { + const latest = state.attempts.findLast(attempt => attempt.level === level.level); + if (latest?.outcome === 'inconclusive') { + level.graded = false; + level.score = null; + level.max = null; + level.selection = latest.selectionSha256 ? { sha256: latest.selectionSha256 } : null; + if (level.outcome?.reason !== latest.reason + || ['passed', 'app_failure'].includes(level.outcome.kind)) { + const kind = latest.category === 'interrupted' ? 'ungraded' + : latest.category === 'inconclusive_evidence' ? 'inconclusive' + : runOutcomeKind(latest.category ?? 'harness_failure'); + level.outcome = { kind, phase: 'progression', reason: latest.reason ?? null, + appFailures: [], inconclusive: [], + harnessFailures: kind === 'harness_failure' ? [latest.reason ?? 'progression failed'] : [] }; + } + } + if (level.repair) { + const used = state.attempts.filter(attempt => attempt.level === level.level && attempt.repair).length; + level.repairs = used - (level.priorRepairs ?? 0); + level.repair.used = used; + level.repair.limit = Math.max(level.repair.limit, used); + level.repair.nodeRepairs = dependencyLevelRepairRecords(state, level.level); + if (level.cumulativeRepairs !== undefined) level.cumulativeRepairs = used; + if (latest?.outcome === 'inconclusive') level.repair.status = 'ungraded'; + else if (level.outcome.kind === 'passed') { + level.repair.status = used ? 'corrected' : 'not-needed'; + level.repair.stopReason = used ? 'passed' : 'not-needed'; + level.stalled = false; + } + } + } +} + +export function mergeFeatureLevelRecord(previous: RunLevelRecord | null, + current: RunLevelRecord): RunLevelRecord { + if (!previous) return current; + const buildSessions: RunSessionRecord[] = [ + ...(previous.buildSessions ?? []), + ...(current.buildSessions ?? []), + ]; + const repairSessions = [...(previous.repairSessions ?? []), ...(current.repairSessions ?? [])]; + const sessionTotals = summarizeSessions([...buildSessions, + ...(current.resumeSession ?? previous.resumeSession ? [current.resumeSession ?? previous.resumeSession!] : []), + ...repairSessions]); + const repairs = (previous.repairs ?? 0) + (current.repairs ?? 0); + const repair = current.repair ? { + ...current.repair, + limit: Math.max(previous.repair?.limit ?? 0, + (previous.repairs ?? 0) + current.repair.limit), + used: repairs, + } : previous.repair; + const merged: RunLevelRecord = { + ...previous, + ...current, + buildSessions, + buildCostUsd: addCostUsd(previous.buildCostUsd, current.buildCostUsd), + repairSessions, + repairCostUsd: addCostUsd(previous.repairCostUsd, current.repairCostUsd), + repairHistory: [...(previous.repairHistory ?? []), ...(current.repairHistory ?? [])], + repairs, + repair, + sessionTotals, + tokens: sessionTotals.tokens, + usage: sessionTotals.usage, + turns: sessionTotals.turns, + promptBytes: sessionTotals.promptBytes, + tokensPerTurn: sessionTotals.turns + ? Math.round(sessionTotals.tokens / sessionTotals.turns) : null, + thinking: sessionTotals.thinking, + costUsd: addCostUsd(previous.costUsd, current.costUsd), + durationSec: (previous.durationSec ?? 0) + (current.durationSec ?? 0), + }; + return merged; +} + +function mutationControlArgs(args: BenchArgs): MutationControlArgs { + if (!args.out || !args.mutations || !args.backend || !args.parentAttemptId) { + throw new Error('mutation control has incomplete run identity'); + } + return { levelList: args.levelList, out: args.out, recipe: args.recipe, + recipeTasks: args.recipeTasks, mutations: args.mutations, backend: args.backend, + track: args.track, runIndex: args.runIndex, parentAttemptId: args.parentAttemptId, + mutationShardIndex: args.mutationShardIndex, mutationShardCount: args.mutationShardCount, + mutationResumeFrom: args.mutationResumeFrom, mutationCheckpointOut: args.mutationCheckpointOut, + mutationBaselineBundle: args.mutationBaselineBundle, + expectedMutationCalibration: args.expectedMutationCalibration, + mutationMaxRuntimeMinutes: args.mutationMaxRuntimeMinutes, + mutationImageId: args.mutationImageId }; +} + +function mutationOutcome(value: unknown): RunOutcome | null { + if (value === null || value === undefined) return null; + if (!object(value)) { + throw new Error('mutation control artifact outcome is invalid'); + } + return { kind: runOutcomeKind(value.kind), + ...(typeof value.phase === 'string' ? { phase: value.phase } : {}), + ...(typeof value.reason === 'string' ? { reason: value.reason } : {}) }; +} + +function recipeRequestIdentity(value: unknown): { recipeSha256: string; selectionSha256: string; + taskPacks: unknown; taskSha256: string } { + if (!object(value) || !object(value.recipe) || !object(value.selection) || !object(value.task) + || typeof value.recipe.contentSha256 !== 'string' || typeof value.selection.sha256 !== 'string' + || typeof value.task.sha256 !== 'string') { + throw new Error('recipe task request has no complete identity'); + } + return { recipeSha256: value.recipe.contentSha256, selectionSha256: value.selection.sha256, + taskPacks: value.selection.taskPacks, taskSha256: value.task.sha256 }; +} + +function snapshotSource(appDir: string, to: string): void { + snapshotAppSource(appDir, to); +} + +// Match the database and registry endpoints supplied to the coding container. +// A matching port on another host is not owned by this run. +export function runAuditNetworkContext(track: Parameters[0], + args: { backend: string; runIndex: number }, lease: BackendLease): { ownEndpoints: string[]; isolatedLoopback: boolean } { + const ports = portsFor(track, args.backend, args.runIndex); + const databaseUrl = leasedDatabaseEnvironment(STACK_ADAPTER_REGISTRY.get(args.backend), { + database: lease.resources.database, networkMode: lease.resources.buildContainer?.networkMode, + lease, + }).DATABASE_URL; + const urls = [ports.vite, ports.express].filter((port): port is number => port !== null) + .map(port => `http://127.0.0.1:${port}`); + urls.push(...[databaseUrl, lease.resources.serverUri, packageRegistryEnvironment(packageRegistry(), + lease.resources.buildContainer?.networkMode, lease.resources.network).NPM_CONFIG_REGISTRY].filter((url): url is string => !!url)); + // Only endpoint authority leaves this process. Database credentials stay private. + // A loopback endpoint is also owned at each of the attempt's own network addresses, + // which is how a coding agent reaches its own application by bridge address. + const ownAddresses = lease.resources.network?.ownAddresses ?? []; + const ownEndpoints = [...new Set(urls.flatMap(value => { + const url = new URL(value); + const port = url.port || (url.protocol === 'https:' ? '443' : '80'); + const hosts = /^(?:127\.0\.0\.1|localhost|0\.0\.0\.0)$/.test(url.hostname) + ? [url.hostname, ...ownAddresses] : [url.hostname]; + return hosts.map(host => `${host}:${port}`); + }))]; + // The authenticated lease records the inspected coding container's namespace. + // A transcript's cwd or a Docker bridge alone does not prove isolation. + const network = lease.resources.network; + const build = lease.resources.buildContainer; + const isolatedLoopback = !!(network?.namespaceContainerId + && lease.resources.container?.owned && lease.resources.container.id === network.namespaceContainerId + && network.firewallSha256 && network.firewallInstalledAt + && build?.owned && build.networkMode === `container:${network.namespaceContainerId}`); + return { ownEndpoints, isolatedLoopback }; +} + +// Check contamination after every coding session. File-tool permissions do not +// govern shell reads, so the transcript audit remains a separate hard gate. +function auditContamination(appDir: string, network: ReturnType, + expectTranscripts: boolean): ContaminationAudit | null { + // A non-billable adapter runs no provider session and leaves no transcript; + // there is nothing to audit and nothing that could have been read. + if (!expectTranscripts) return null; + const args = [join(ROOT, 'dist', 'commands', 'leak-audit.js'), '--app', appDir, '--json', + '--own-endpoints', network.ownEndpoints.join(','), ...(network.isolatedLoopback ? ['--isolated-loopback'] : [])]; + let firstFailure: unknown = null; + for (let attempt = 1; attempt <= 2; attempt++) { + try { + const audit = sh('node', args, { stdio: 'pipe' }); + const entries = parseLeakAudit(audit); + if (entries.length === 0) { + return { kind: 'harness_failure', + evidence: ['no session transcript was found to audit'], + verdict: 'SCORES NOT USABLE — nothing verified this build stayed inside its directory.' }; + } + const escapes = entries.flatMap(entry => entry.hits); + const serious = escapes.filter(h => /GRADER|CONTRACT|BENCHMARK NOTES|PROMPTS|NETWORK/.test(h.kind)); + if (firstFailure) { + console.error(` warning: contamination audit passed on retry after: ${auditFailureSummary(firstFailure)}`); + } + if (!serious.length) return null; + return { kind: 'contaminated', + evidence: [...new Set(serious.map(h => `${h.kind}: ${h.path.split('/').slice(-2).join('/')}`))].slice(0, 8), + verdict: 'SCORES NOT USABLE — the audit detected restricted file or network access attempts; see the evidence categories.' }; + } catch (error) { + firstFailure ??= error; + if (attempt === 2) { + // An audit that could not run is not a pass. Keep the process details so + // the failure can be repaired without another paid reproduction. + return { kind: 'harness_failure', + evidence: [`audit did not run after retry: ${auditFailureSummary(error)}`], + verdict: 'SCORES NOT USABLE — nothing verified this build stayed inside its directory.' }; + } + } + } + return null; +} + +export function auditFailureSummary(error: unknown): string { + const failure = object(error) ? error : {}; + const message = errorMessage(error).split(/\r?\n/)[0] ?? ''; + const stderrLines = String(failure.stderr ?? '').trim().split(/\r?\n/).filter(Boolean); + const stderr = stderrLines.find(line => /(?:error|eacces|permission denied|failed)/i.test(line)) + ?? stderrLines[0]; + const details = [ + Number.isInteger(failure.status) ? `exit ${String(failure.status)}` : null, + failure.signal ? `signal ${String(failure.signal)}` : null, + stderr ? `stderr: ${stderr}` : null, + ].filter(Boolean); + return details.length ? `${message} (${details.join('; ')})` : message; +} + +const sh = (cmd: string, args: readonly string[], + opts: Omit = {}): string => + execFileSync(cmd, [...args], { + encoding: 'utf8', maxBuffer: 64 * 1024 * 1024, timeout: COMMAND_TIMEOUT_MS, ...opts, + }); + +let activeAgentCancellation: AbortController | null = null; +// Set once a run owns resources. The top-level rejection handler invokes this +// directly; relying only on process 'exit' made cleanup best-effort precisely +// when an awaited build rejected unexpectedly. +let emergencyTeardown: (() => void) | null = null; + +export function parseAgentProcessResult(stdout: string, stderr: string, processError: unknown, + request: AgentRequest): ValidatedAgentResult { + const resultLine = stdout.trim().split('\n').pop(); + let result: ValidatedAgentResult; + try { + if (!resultLine) throw new Error('agent returned no result line'); + result = validateAgentResult(JSON.parse(resultLine), request); + } catch (resultError) { + const stdoutTail = stdout.trim().slice(-2000) || ''; + const stderrTail = stderr.trim().slice(-4000) || ''; + const processDetail = processError ? `agent process failed: ${errorMessage(processError)}\n` : ''; + throw new Error(`${processDetail}agent returned an invalid result: ${errorMessage(resultError)}\n` + + `agent stdout tail:\n${stdoutTail}\nagent stderr tail:\n${stderrTail}`); + } + if (processError && result.ok) { + throw new Error(`agent process failed after reporting success: ${errorMessage(processError)}`); + } + return result; +} + +export async function runAgent( + args: BenchArgs, + adapter: AgentAdapter, + mode: AgentMode, + level: number, + appDir: string, +): Promise { + if (!args.backend || !args.model) throw new Error('agent run requires backend and model'); + const remainingBudget = args.maxBudgetUsd == null ? null + : addCostUsd(args.maxBudgetUsd, -(args.spentBudgetUsd ?? 0)); + if (remainingBudget !== null && remainingBudget <= 0) { + throw new Error(`attempt cost cap of $${args.maxBudgetUsd} was exhausted before ${mode} L${level}`); + } + if (remainingBudget !== null && adapter.costLimit === 'unsupported') { + throw new Error(`agent adapter ${adapter.id} cannot enforce --max-budget-usd`); + } + const recipeTask = args.recipeTasks?.get(level)?.agentRequest + ?? args.recipeTasks?.get(level)?.request ?? null; + const request: AgentRequest = { mode, level, app: appDir, backend: args.backend, track: args.track, + runIndex: args.runIndex, model: args.model, guidance: args.guidance, skills: args.skills, + productionQuality: args.productionQuality, + ...(adapter.usesStackSkills + ? { skillIdentity: args.condition?.guidance.skills[args.backend] } : {}), + recipe: agentRecipeIdentity(args.recipe, recipeTask), + guidanceDocument: args.guidanceDocument, + credentialAliases: args.condition?.guidance?.credentialAliases ?? {}, + recipeTask, pricing: args.pricing, providerRoute: args.providerRoute, maxOutputTokens: args.maxOutputTokens, + maxBudgetUsd: remainingBudget, adapterCostLimit: adapter.costLimit }; + const argv = agentRequestArgv(adapter, request); + if (args.apiKey && !adapter.apiKeyEnvironmentVariable) { + throw new Error(`agent adapter ${adapter.id} does not accept an API key`); + } + const env = { ...process.env }; + if (args.apiKeyFile) env.STACK_BENCH_AGENT_API_KEY_FILE = args.apiKeyFile; + if (args.apiKey) { + const credentialName = adapter.apiKeyEnvironmentVariable; + if (!credentialName) throw new Error(`agent adapter ${adapter.id} does not accept an API key`); + env[credentialName] = args.apiKey; + } + const supervised = campaignProviderContinuationContext(env) !== null; + const capture = mkdtempSync(join(dirname(appDir), '.agent-output-')); + const cancellation = new AbortController(); + activeAgentCancellation = cancellation; + try { + const processResult = await runBounded(process.execPath, argv, { + env, stdio: 'ignore', timeoutMs: supervised ? null : adapter.deadlineMs, + signal: cancellation.signal, + logs: { stdout: join(capture, 'stdout'), stderr: join(capture, 'stderr'), maxBytes: 64 * 1024 * 1024 }, + }); + const processError = processResult.error ?? (processResult.timedOut + ? new Error(`agent deadline exceeded after ${adapter.deadlineMs} ms`) + : processResult.cancelled ? new Error('agent process cancelled') + : !processResult.ok ? new Error(`agent exited ${processResult.code ?? processResult.signal}`) : null); + if (Object.values(processResult.logs ?? {}).some(log => log.truncated)) { + throw new Error('agent output exceeded the 64 MiB capture limit'); + } + const result = parseAgentProcessResult(readFileSync(join(capture, 'stdout'), 'utf8'), + readFileSync(join(capture, 'stderr'), 'utf8'), processError, request); + args.spentBudgetUsd = addCostUsd(args.spentBudgetUsd, result.costUsd); + return result; + } finally { + if (activeAgentCancellation === cancellation) activeAgentCancellation = null; + rmSync(capture, { recursive: true, force: true }); + } +} + +interface GradeCheck { + stableKey: string; + executionId?: string; + source?: string; +} + +interface GradeRecipeTask { + request: UnknownRecord; + selection: { checks: readonly GradeCheck[] } + | { scoredChecks: readonly GradeCheck[]; observedChecks?: readonly GradeCheck[] }; +} + +/** The aliases grading expects: the run's own when set, else the condition's. */ +function gradingCredentialAliases(args: GradeArguments): Record | undefined { + return args.gradingCredentialAliases ?? args.condition?.guidance?.credentialAliases; +} + +function checksForGrade(task: GradeRecipeTask | undefined, observation: GradeOptions['observation']): + readonly GradeCheck[] { + if (!task) return []; + if ('scoredChecks' in task.selection) { + return observation === 'observed' + ? task.selection.observedChecks ?? [] : task.selection.scoredChecks; + } + return task.selection.checks; +} + +type GradeArguments = Pick & { + recipeTasks?: ReadonlyMap; + progression?: { identity: { policy?: string } }; + condition?: { guidance?: { credentialAliases?: Record } }; + gradingCredentialAliases?: Record; +}; + +export function gradeArgv( + args: GradeArguments, + appDir: string, + url: string, + label: string, + level: number, + track: Track, + parentAttemptId: string, + options: GradeOptions = {}, +): string[] { + const { observation = 'scored', out = null, sourceSha256 = null, + applicationFailure = null } = options; + if (!args.backend) throw new Error('grading requires a backend'); + const restartSpec = restartSpecFor(args, appDir, track); + const task = options.recipeTask ?? args.recipeTasks?.get(level); + return [compiledEntrypoint('commands', 'run-suite.js'), '--app', appDir, '--url', url, + '--backend', args.backend, '--label', label, '--level', String(level), + '--track', args.track, + '--run-index', String(args.runIndex), + '--parent-attempt-id', parentAttemptId, + '--observation', observation, + '--out', privateGradingDirectory(appDir, out), + ...(sourceSha256 ? ['--source-sha256', sourceSha256] : []), + ...(args.recipe ? ['--recipe', args.recipe] : []), + ...(task ? ['--recipe-task-json', JSON.stringify(task.request)] : []), + ...(gradingCredentialAliases(args) + ? ['--credential-aliases-json', JSON.stringify(gradingCredentialAliases(args))] : []), + ...(applicationFailure + ? ['--application-failure-json', JSON.stringify(applicationFailure)] : []), + ...(observation === 'scored' && args.recipeTasks && !args.progression + ? ['--regression-checks-json', JSON.stringify([...args.recipeTasks.entries()] + .filter(([priorLevel]) => priorLevel < level) + .flatMap(([, priorTask]) => checksForGrade(priorTask, 'scored') + .map(check => check.stableKey)))] : []), + ...(args.media && observation === 'scored' ? [] : ['--no-media']), + ...(!STACK_ADAPTER_REGISTRY.get(args.backend).runPolicy.resetEnabled + ? ['--no-reset'] + : ['--restart-spec', JSON.stringify(restartSpec)])]; +} + +export function archiveCandidateGrade(appDir: string, outputDir: string, label: string): void { + const gradingDirectory = privateGradingDirectory(appDir); + if (!existsSync(gradingDirectory)) return; + cpSync(gradingDirectory, privateGradingDirectory(appDir, join(outputDir, 'candidate-grades', label)), { + recursive: true, + filter: source => !/[\\/]media([\\/]|$)/.test(source), + }); +} + +export async function gradeWithRetry({ appDir, outputDir, label, archiveLabel, runGrade, + retry = true }: { + appDir: string; outputDir: string; label: string; archiveLabel: string; + runGrade: (label: string) => GradeBundlePayload | null | Promise; + retry?: boolean; +}): Promise { + const bundle = await runGrade(label); + if (!retry || levelGradeIsUsable(classifyBundle(bundle))) return bundle; + archiveCandidateGrade(appDir, outputDir, archiveLabel); + console.log(' grade did not complete; retrying the same source once'); + return runGrade(`${label}-retry`); +} + +function grade( + args: BenchArgs, + appDir: string, + url: string, + label: string, + level: number, + track: Track, + parentAttemptId: string, + options: GradeOptions = {}, +): GradeBundlePayload | null { + const out = privateGradingDirectory(appDir, options.out); + const source = hashAppSource(appDir); + const argv = gradeArgv(args, appDir, url, label, level, track, parentAttemptId, { + ...options, sourceSha256: options.sourceSha256 ?? source.sha256, + }); + const bundle = join(out, ARTIFACT_FILE.gradeBundle); + rmSync(bundle, { force: true }); + const task = options.recipeTask ?? args.recipeTasks?.get(level); + const currentChecks = checksForGrade(task, options.observation); + const regressionChecks = options.observation === 'observed' || args.progression + ? [] + : [...(args.recipeTasks?.entries() ?? [])] + .filter(([priorLevel]) => priorLevel < level) + .flatMap(([, priorTask]) => checksForGrade(priorTask, 'scored')); + const sourceCount = task + ? selectedGradingSourceCount(currentChecks, regressionChecks) + : suitesFor(track, level).length; + try { + sh('node', argv, { stdio: 'inherit', timeout: gradingRunTimeoutMs(sourceCount) }); + } catch { /* a current bundle may still explain a scored failure */ } + return existsSync(bundle) + ? readArtifactPayload(bundle, { expectedKind: 'grade_bundle' }) : null; +} + +function restartSpecFor(args: Pick, + appDir: string, track: Track): RuntimeControlSpec { + if (!args.backend) throw new Error('restart specification requires a backend'); + const port = portsFor(track, args.backend, args.runIndex).vite ?? null; + if (port == null) throw new Error(`stack ${args.backend} has no application port`); + return { backend: args.backend, app: appDir, port: Number(port), probe: '' }; +} + +function runMutationControl( + args: BenchArgs, + appDir: string, + url: string, + track: Track, + imageId: string | null, +): MutationControlResult { + if (!args.out || !args.mutations) throw new Error('mutation control requires output and manifest paths'); + const output = join(args.out, ARTIFACT_FILE.mutationControl); + if (!args.mutationResumeFrom || resolve(args.mutationResumeFrom) !== resolve(output)) { + rmSync(output, { force: true }); + } + if (imageId) args.mutationImageId = imageId; + else delete args.mutationImageId; + const argv = mutationControlArgv(mutationControlArgs(args), appDir, url, track); + let processError = null; + try { sh(process.execPath, argv, { + stdio: 'inherit', timeout: mutationControlTimeoutMs(args.mutationMaxRuntimeMinutes), + }); } + catch (error) { processError = errorMessage(error).split('\n')[0] ?? null; } + if (!existsSync(output)) { + return { ok: false, artifact: output, processError, + outcome: { kind: 'harness_failure', phase: 'mutation-control', + reason: processError ?? 'mutation runner produced no artifact' } }; + } + const artifact = readArtifactPayload(output, { expectedKind: 'mutation_control' }); + return { ok: artifact.ok === true && !processError, artifact: output, + processError, summary: artifact.summary ?? null, outcome: mutationOutcome(artifact.outcome), + results: artifact.results ?? [] }; +} + +function validateMutationInput(args: BenchArgs): void { + if (!args.mutations) return; + if (!args.app) throw new Error('--mutations requires an explicit pristine --app'); + const manifest = JSON.parse(readFileSync(args.mutations, 'utf8')); + if (!/^[a-f0-9]{64}$/.test(manifest.fixtureSha256 ?? '')) { + throw new Error('mutation manifest has no valid fixtureSha256'); + } + const fixture = hashDirectory(args.app); + if (fixture.sha256 !== manifest.fixtureSha256) { + throw new Error(`mutation manifest targets fixture ${manifest.fixtureSha256}, not ${fixture.sha256}`); + } +} + +export function inspectGradeSource(directory: string, + options: { level?: number; checkKeys?: string[] } = {}) { + const root = realpathSync(directory); + const runPath = join(root, ARTIFACT_FILE.run); + const parent = readArtifact(runPath, { expectedKind: 'benchmark_run' }); + const run = parent.payload; + if (!object(run.mode) + || !['sequential', 'dependency'].includes(String(run.mode.id)) || run.contaminated) { + throw new Error('--grade-from requires an uncontaminated sequential or dependency run'); + } + const dependency = run.mode.id === 'dependency'; + if (!parent.timestamps.completedAt) { + const recoveryPath = join(root, ARTIFACT_FILE.recovery); + if (!dependency || !existsSync(recoveryPath)) { + throw new Error('unfinished --grade-from requires a recovered dependency run and a completed candidate grade'); + } + const recovery = readArtifact<{ runId: string; backend: string; status: string; + cleanup: { succeeded: boolean; retained: boolean } }>(recoveryPath, { expectedKind: 'recovery' }); + if (recovery.attempt.parentId !== parent.id || recovery.payload.runId !== parent.id + || recovery.payload.backend !== run.backend || recovery.payload.status !== 'clean' + || recovery.payload.cleanup?.succeeded !== true || recovery.payload.cleanup.retained !== false) { + throw new Error('unfinished --grade-from recovery does not prove cleanup of its parent'); + } + } + if (dependency && (!Number.isSafeInteger(options.level) || options.level! < 1)) { + throw new Error('dependency --grade-from requires a positive --grade-level'); + } + if (dependency && !options.checkKeys?.length) throw new Error('dependency --grade-from requires explicit --check keys'); + if (!dependency && (options.level !== undefined || run.levels.length !== 1)) { + throw new Error('sequential --grade-from requires a single level and does not accept --grade-level'); + } + const levels = dependency ? run.levels.filter(item => item.level === options.level) : run.levels; + if (levels.length !== 1 || (dependency && run.mode.workSelection === 'feature')) { + throw new Error('saved replay requires exactly one unambiguous first-build candidate at the selected depth'); + } + const level = levels[0]!; + if (!parent.identities.agentAdapter?.id || !Number.isSafeInteger(run.backendLease?.runIndex) + || run.backendLease.runIndex < 0 || !run.runtime?.buildImage) { + throw new Error('saved run lacks its agent, runtime image, or run index'); + } + const serverUri = run.backend === 'spacetime' + ? loopbackHttpUri(run.backendLease.resources?.serverUri).origin : null; + const checkpoint = level.checkpoint; + const condition = run.condition as BenchArguments['condition']; + let declared = condition?.requested?.levels?.find(item => item.level === level.level); + if ((!dependency && !checkpoint) || !declared || declared.selection.schemaVersion !== 3 + || !declared.task.contractSha256 || !declared.task.requirementSha256 + || !Array.isArray(declared.selection.requested.features) + || !Array.isArray(declared.selection.scoredChecks)) { + throw new Error('saved run lacks a source checkpoint or a bound modular grading scope'); + } + const child = (name: string): string => { + const path = realpathSync(resolve(root, name)); + const rel = relative(root, path); + if (!rel || rel === '..' || rel.startsWith(`..${sep}`) || isAbsolute(rel)) throw new Error('saved checkpoint path escapes its execution'); + return path; + }; + const sourceDirectory = dependency ? `first-build-l${level.level}` : checkpoint!.directory; + const sourcePath = child(sourceDirectory); + assertPlainAppSourceTree(sourcePath); + const source = hashAppSource(sourcePath); + let candidate = null; + if (dependency) { + const gradePath = `first-build-l${level.level}-grading/bundle.json`; + const gradeFile = child(gradePath); + const grade = readArtifact(gradeFile, { expectedKind: 'grade_bundle' }); + const expected = level.firstBuild?.source; + if (!object(expected) || source.sha256 !== expected.sha256 || source.files.length !== expected.files + || grade.attempt.parentId !== parent.id || grade.payload.source?.sha256 !== source.sha256 + || grade.payload.backend !== run.backend || grade.payload.track !== run.track + || grade.payload.level !== level.level || grade.payload.observation !== 'scored' + || canonicalDefinitionJson(grade.identities.engine) !== canonicalDefinitionJson(parent.identities.engine) + || grade.identities.recipe?.id !== declared.recipe.id + || grade.identities.recipe?.sha256 !== declared.recipe.contentSha256 + || grade.payload.selection?.schemaVersion !== 3 + || grade.payload.selection.sha256 !== level.selection?.sha256 + || canonicalDefinitionJson(grade.payload.selection) !== canonicalDefinitionJson(level.selection) + || !Array.isArray(grade.payload.selection.requested?.features) + || !Array.isArray(grade.payload.selection.scoredChecks)) { + throw new Error('saved first-build source or grade does not match its parent run and candidate scope'); + } + declared = { ...declared, selection: grade.payload.selection }; + candidate = { kind: 'first-build', directory: sourceDirectory, level: level.level, + grade: { path: gradePath, sha256: sha256(readFileSync(gradeFile)), id: grade.id, + identities: grade.identities }, outcome: level.firstBuild?.outcome ?? null }; + } else { + const saved = readArtifact<{ source: { directory: string; sha256: string; files: number }; + backend: string; track: string; level: number; selectionSha256: string }>(child(checkpoint!.artifact), + { expectedKind: 'source_checkpoint' }); + if (saved.attempt.parentId !== parent.id || saved.payload.backend !== run.backend + || saved.payload.track !== run.track || saved.payload.level !== level.level + || saved.payload.source.directory !== checkpoint!.directory + || saved.payload.source.sha256 !== checkpoint!.sha256 || saved.payload.source.files !== checkpoint!.files + || saved.payload.selectionSha256 !== declared.selection.sha256 + || source.sha256 !== checkpoint!.sha256 || source.files.length !== checkpoint!.files) { + throw new Error('saved source or checkpoint does not match its parent run'); + } + } + if (options.checkKeys?.some(key => !declared.selection.scoredChecks!.some(check => check.stableKey === key))) { + throw new Error('regrade checks must belong to the original scored scope'); + } + const aliases = condition?.guidance.credentialAliases; + if (!aliases || Object.values(aliases).some(value => typeof value !== 'string')) { + throw new Error('saved run lacks valid grading credential aliases'); + } + return { root, parent, declared, dependency, candidate, serverUri, sourcePath, source: { sha256: source.sha256, files: source.files.length }, + runSha256: sha256(readFileSync(runPath)), aliases }; +} + +export function pendingRunSnapshot(run: BenchmarkRunRecord, pending: RunLevelRecord | null, + costComplete: boolean): BenchmarkRunRecord { + const snapshot = { ...run, levels: [...run.levels] }; + if (pending) { + const index = snapshot.levels.findIndex(level => level.level === pending.level); + const record = mergeFeatureLevelRecord(index < 0 ? null : snapshot.levels[index]!, pending); + if (index < 0) snapshot.levels.push(record); + else snapshot.levels[index] = record; + if (!['harness_failure', 'provider_failure'].includes(run.outcome?.kind ?? '')) snapshot.outcome = { kind: 'ungraded', phase: 'interrupted-level', + reason: 'level has not completed', appFailures: [], inconclusive: [], harnessFailures: [] }; + } + finalizeRunTotals(snapshot, Date.parse(run.startedAt), { costComplete }); + return snapshot; +} + +async function main() { + let pendingLevel: RunLevelRecord | null = null; + let sessionInFlight = false; + let runCostComplete = true; + const persistRun = (path: string, value: unknown) => { + if (pendingLevel || sessionInFlight) { + return writeRunJson(path, pendingRunSnapshot(value as BenchmarkRunRecord, + pendingLevel, runCostComplete && !sessionInFlight)); + } + return writeRunJson(path, value); + }; + const args: BenchArgs = { + ...parseBenchArguments(process.argv), + recipeTasks: new Map(), + recipeBindings: new Map(), + }; + const regrade = args.gradeFrom ? inspectGradeSource(args.gradeFrom, + { level: args.gradeLevel, checkKeys: args.checkKeys }) : null; + if (regrade) { + const { parent, declared, aliases } = regrade; + const requested = declared.selection.requested; + Object.assign(args, { backend: parent.payload.backend, track: parent.payload.track, + runIndex: parent.payload.backendLease.runIndex, + levels: String(declared.level), levelList: [declared.level], recipe: declared.recipe.id, + agentAdapter: parent.identities.agentAdapter!.id, model: parent.payload.model, + providerRoute: parent.payload.providerRoute, + maxOutputTokens: parent.payload.maxOutputTokens, + featureIds: requested.features, checkKeys: args.checkKeys.length ? args.checkKeys : requested.checks, + requestedSpecifications: requested.specifications?.requested ?? [], + expectedSpecifications: requested.specifications?.expected ?? [], + observedSpecifications: [], gradingCredentialAliases: aliases }); + if (declared.selection.observedChecks?.length) throw new Error('--grade-from does not support observed checks'); + const output = resolve(args.out!); + for (let path = output; dirname(path) !== path; path = dirname(path)) { + if (existsSync(path) && lstatSync(path).isSymbolicLink()) { + throw new Error('regrade output must not pass through a symbolic link'); + } + } + const overlaps = (base: string, target: string) => { + const rel = relative(base, target); + return !rel || (rel !== '..' && !rel.startsWith(`..${sep}`) && !isAbsolute(rel)); + }; + if (overlaps(regrade.root, output) || overlaps(output, regrade.root) + || (existsSync(output) && readdirSync(output).length)) { + throw new Error('--grade-from requires an empty output directory outside the original execution'); + } + if (process.env.STACK_BENCH_IMAGE && process.env.STACK_BENCH_IMAGE !== parent.payload.runtime.buildImage) { + throw new Error('regrade build image differs from the original run'); + } + process.env.STACK_BENCH_IMAGE = parent.payload.runtime.buildImage; + if (regrade.serverUri) process.env.STACK_BENCH_STDB_URI = regrade.serverUri; + } + let repairGrant = null; + if (args.repairFrom) { + const repairLevel = args.repairLevel; + if (typeof repairLevel !== 'number' || !Number.isSafeInteger(repairLevel) || repairLevel < 1) { + throw new Error('--repair-from requires a positive --repair-level'); + } + repairGrant = createRepairGrant(args.repairFrom, + { level: repairLevel, repairs: args.repairs }); + const config = repairGrant.configuration; + if (config.buildImage && process.env.STACK_BENCH_IMAGE + && config.buildImage !== process.env.STACK_BENCH_IMAGE) { + throw new Error('repair continuation build image differs from its parent run'); + } + if (config.buildImage) process.env.STACK_BENCH_IMAGE = config.buildImage; + Object.assign(args, { + backend: config.backend, + track: config.track, + recipe: config.recipe, + levels: String(config.level), + levelList: [config.level], + runIndex: config.runIndex, + agentAdapter: config.agentAdapter, + model: config.model, + providerRoute: config.providerRoute, + maxOutputTokens: config.maxOutputTokens, + guidance: config.guidance, + guidanceDocument: config.guidanceDocument, + productionQuality: config.condition?.productionQuality === true || (!config.condition && config.productionQuality === true), + condition: config.condition, + selectionRequest: campaignSelection(config.selectionRequest, 'repair configuration.selectionRequest'), + skills: config.skills, + packIds: [...(campaignSelection(config.selectionRequest, + 'repair configuration.selectionRequest').packs ?? [])], + checkKeys: [...(campaignSelection(config.selectionRequest, + 'repair configuration.selectionRequest').checks ?? [])], + featureIds: [], + requestedSpecifications: [], + expectedSpecifications: [], + observedSpecifications: [], + seedFrom: repairGrant.sourcePath, + url: config.url, + parentAttemptId: repairGrant.parent.id, + repairGrant, + }); + } + if (!args.backend) throw new Error('benchmark run requires a backend'); + const stackAdapter = STACK_ADAPTER_REGISTRY.get(args.backend); + const materializeCodingOutput = stackAdapter.id !== 'stub'; + const agentAdapter = AGENT_ADAPTER_REGISTRY.get(args.agentAdapter); + args.providerRoute = validateProviderRoute(agentAdapter.provider, args.providerRoute); + args.maxOutputTokens = validateProviderOutputLimit(agentAdapter.provider, args.maxOutputTokens); + // Credential aliases keep the fixture passwords out of an agent's prompt, + // so grading expects the aliases. A reference fixture is the fixture itself, + // seeded with the real credentials, and is graded with them. + if (!regrade && agentAdapter.gradesWithFixtureCredentials) args.gradingCredentialAliases = {}; + if (process.env.STACK_BENCH_APPLIANCE !== '1' && agentAdapter.costLimit !== 'non-billable') { + throw new Error(`agent adapter ${agentAdapter.id} requires the Docker appliance`); + } + if (repairGrant) { + const currentAgent = agentAdapterIdentity(agentAdapter); + const parentAgent = repairGrant.parentArtifact.identities.agentAdapter; + if (currentAgent.id !== parentAgent?.id || currentAgent.version !== parentAgent?.version + || currentAgent.sha256 !== parentAgent?.sha256) { + throw new Error('repair continuation agent adapter differs from its parent run'); + } + if (stackAdapter.id !== repairGrant.parentArtifact.identities.stackAdapter?.id + || stackAdapter.version !== repairGrant.parentArtifact.identities.stackAdapter?.version) { + throw new Error('repair continuation stack adapter differs from its parent run'); + } + } + if (!regrade) applyAgentCredential(args, agentAdapter); + args.model ??= agentAdapter.defaultModel; + if (!args.model) throw new Error(`agent adapter ${agentAdapter.id} has no default model`); + if (args.pricing !== undefined) { + args.pricing = validatePricingAuthority(args.pricing, { at: '--pricing-json' }); + } else if (args.maxBudgetUsd != null && agentAdapter.costLimit === 'native') { + const rates = claudeRatesForModel(args.model); + if (!rates) throw new Error(`no default pricing is recorded for model ${args.model}`); + args.pricing = validatePricingAuthority({ unit: PRICING_UNIT, rates }, + { at: 'default pricing' }); + } else { + args.pricing = null; + } + if (args.retainBackend && !stackAdapter.runPolicy.retainHostSupported) { + throw new Error(`stack adapter ${args.backend} does not support --retain-backend`); + } + const stackRuntime = stackAdapter.orchestrator.config( + { root: ROOT, env: process.env, helpers: { exists: existsSync } }); + Object.assign(process.env, stackRuntime.environment); + process.env.STACK_BENCH_NODE_BIN = process.platform === 'win32' ? 'node.exe' : process.execPath; + const track = loadTrack(args.track); + const auditsTranscripts = agentAdapter.costLimit !== 'non-billable'; + // Resolve the requested scope for every level before probing the sandbox, + // acquiring a backend lease or paying for a build. A pack that exists at L2 + // but not L1 is not a late grading surprise; it is an invalid run request. + args.selectionRequest ??= { packs: [...args.packIds], checks: [...args.checkKeys] }; + for (const level of args.levelList) { + const declared = args.condition?.requested?.levels?.find(entry => entry.level === level) ?? null; + const modularSelection = args.selectionRequest.levels?.find(entry => entry.level === level) ?? null; + if (declared?.selection?.schemaVersion === 3) { + const expected = args.featureCatalog + ? { level, recipe: declared.recipe.id } + : { level, recipe: declared.recipe.id, + features: declared.selection.requested.features, + checks: declared.selection.requested.checks }; + if (canonicalDefinitionJson(modularSelection) !== canonicalDefinitionJson(expected)) { + throw new Error(`campaign selection changed before L${level}`); + } + } else if (modularSelection) { + throw new Error(`campaign selection declares modular L${level} without a modular condition`); + } + const declaredRecipe = declared?.recipe.id ?? null; + const binding = resolveRecipeRelease(track, level, declaredRecipe ?? args.recipe); + if (!binding && (args.packIds.length || args.checkKeys.length)) { + throw new Error(`L${level} has no recipe release, so --pack/--check cannot be resolved`); + } + if (binding) { + args.recipeBindings.set(level, binding); + if (args.featureCatalog) { + validateProgressionCampaignLevelScope(binding, args.featureCatalog, declared, level); + } + const requested = declared?.selection?.requested; + const progressionSelection = args.featureCatalog + ? resolveProgressionRecipeLevelSelection(binding, args.featureCatalog, level, + { cumulative: Boolean(args.progression) }) : null; + const resolved = progressionSelection === null + ? createBoundRecipeTaskRequest(binding, requested?.features + ? { featureIds: requested.features, + requestedSpecifications: requested.specifications?.requested, + expectedSpecifications: requested.specifications?.expected, + observedSpecifications: requested.specifications?.observed, + checkKeys: requested.checks } + : regrade?.dependency ? { ...args, taskMode: regrade.declared.task.mode, + dependencyExpansion: regrade.declared.selection.requested.dependencyExpansion } : args) : null; + const grader = progressionSelection?.grader ?? resolved; + if (!grader) throw new Error(`L${level} has no recipe task request`); + if (args.condition && !declared) { + throw new Error(`study condition does not bind requested L${level}`); + } + const graderIdentity = recipeRequestIdentity(grader.request); + if (declared && (declared.recipe.contentSha256 !== graderIdentity.recipeSha256 + || declared.selection.sha256 !== graderIdentity.selectionSha256 + || JSON.stringify(declared.selection.taskPacks) !== JSON.stringify(graderIdentity.taskPacks) + || declared.task.sha256 !== graderIdentity.taskSha256)) { + throw new Error(`study condition requested scope changed before L${level}`); + } + if (progressionSelection) { + const progressionGrader = progressionSelection.grader; + args.recipeTasks.set(level, { + request: progressionGrader.request, + selection: progressionGrader.selection, + task: progressionGrader.task, + agentRequest: progressionSelection.agent.request, + }); + } else if (resolved) { + args.recipeTasks.set(level, { + ...resolved, + agentRequest: createAgentVisibleTaskRequest(binding, resolved), + }); + } + } + } + if (args.progression) { + const state = progressionEngine.initialize(args.progression.definition); + const declared = args.condition?.requested?.levels + ?.find(entry => entry.level === state.level) ?? null; + const binding = resolveRecipeRelease(track, state.level, + declared?.recipe.id ?? null); + if (!binding) throw new Error(`L${state.level} has no recipe release`); + resolveProgressionRecipeAction(binding, state); + if (!args.progressionOwner) { + throw new Error('live dependency progression requires an exact compiled campaign attempt'); + } + } + if (repairGrant) { + const expectedSelection = repairGrant.level.selection?.sha256 ?? null; + const repairTask = args.recipeTasks.get(repairGrant.level.level); + const resolvedSelection = repairTask ? recipeRequestIdentity(repairTask.request).selectionSha256 : null; + if (resolvedSelection !== expectedSelection) { + throw new Error('repair continuation test selection differs from its parent run'); + } + } + if (regrade) { + const task = args.recipeTasks.get(regrade.declared.level)!; + const keys = (checks: readonly { stableKey: string; points: number }[]) => + checks.map(check => `${check.stableKey}:${check.points}`).sort(); + const selected = 'scoredChecks' in task.selection ? task.selection.scoredChecks : task.selection.checks; + if (regrade.dependency) { + if (canonicalDefinitionJson(selected.map(check => check.stableKey).sort()) + !== canonicalDefinitionJson([...new Set(args.checkKeys)].sort())) { + throw new Error('dependency diagnostic changed the explicitly selected check scope'); + } + } else if (task.task.contractSha256 !== regrade.declared.task.contractSha256 + || task.task.requirementSha256 !== regrade.declared.task.requirementSha256 + || canonicalDefinitionJson(keys(selected)) + !== canonicalDefinitionJson(keys(regrade.declared.selection.scoredChecks!.filter(check => + !args.checkKeys.length || args.checkKeys.includes(check.stableKey))))) { + throw new Error('regrade changed the original product contract or scored check scope'); + } + } + if (!args.selectionRequest.levels && (JSON.stringify(args.selectionRequest.packs) !== JSON.stringify(args.packIds) + || JSON.stringify(args.selectionRequest.checks) !== JSON.stringify(args.checkKeys))) { + throw new Error('campaign pack/check selection changed before execution'); + } + // Caller-owned mutation inputs are pure request data. Reject them before + // checking credentials, Docker, ports, or any other ambient runner state so + // an invalid experiment can never be masked by an unrelated preflight error. + validateMutationInput(args); + // The deterministic adapter/stack is the model-free unit loop. Real runs + // prove the exact requested scope, engine, image, credentials, storage and + // ports before any paid coding session begins. + const performPreflight = (smoke = false) => { + const preflight = args.backend === 'stub' ? null : runPreflight({ + backends: [stackAdapter.id], track: args.track, levels: args.levels, + levelList: args.levelList, runIndex: args.runIndex, agentAdapter: args.agentAdapter, + providerRoute: args.providerRoute, + maxOutputTokens: args.maxOutputTokens, + modelFree: regrade !== null, + guidance: args.guidance, + recipe: args.recipe, + ...(args.condition?.requested ? { requestedScopes: [args.condition.requested] } : {}), + ...(args.featureCatalog ? { featureCatalog: args.featureCatalog } : {}), + ...(args.runMode ? { mode: args.runMode } : {}), + agentSkills: args.skills ?? null, + packIds: args.packIds, checkKeys: args.checkKeys, smoke, + ...(process.env.STACK_BENCH_SUPERVISOR_STATE + ? { supervisorState: process.env.STACK_BENCH_SUPERVISOR_STATE } : {}), + image: process.env.STACK_BENCH_IMAGE ?? DEFAULT_BUILD_IMAGE, + resultsDir: resolve(args.out ?? stackBenchResultsRoot(ROOT)), + }, { ownedLease: { path: leasePath, runId }, env: args.apiKey && agentAdapter.apiKeyEnvironmentVariable + ? { ...process.env, [agentAdapter.apiKeyEnvironmentVariable]: '' } + : process.env }); + if (preflight) writeArtifact(join(outputDir, ARTIFACT_FILE.preflight), { + kind: 'preflight', id: `${runId}-preflight`, + attempt: { id: `${runId}-preflight`, parentId: runId }, + identities: emptyArtifactIdentities({ + agentAdapter: agentAdapterIdentity(agentAdapter), + stackAdapter: { id: stackAdapter.id, version: stackAdapter.version }, + }), + payload: preflight, + }); + if (preflight && !preflight.ok) { + const failures = preflight.checks.filter(check => check.status === 'fail'); + console.error('\nPREFLIGHT FAILED — no model session was started.'); + for (const failure of failures) { + console.error(` ${failure.id}: ${failure.summary}`); + if (failure.remediation) console.error(` hint: ${failure.remediation}`); + } + throw new Error('preflight failed; no model session was started'); + } + if (preflight) console.log(` preflight ... ${preflight.summary.passed} checks passed` + + `${preflight.summary.warnings ? `, ${preflight.summary.warnings} warning(s)` : ''}`); + }; + if (process.env.STACK_BENCH_APPLIANCE === '1') { + console.log(' sandbox ... coding container is isolated from the controller and grading files'); + } + const assignedPorts = portsFor(track, args.backend, args.runIndex); + let url = args.url ?? `http://localhost:${assignedPorts.vite}`; + const runDir = resultsName(track, args.backend, args.runIndex); + const runId = newRunId({ track: args.track, backend: args.backend, runIndex: args.runIndex }); + const artifactLabel = `${runDir}-${runId}`; + // Default results never reuse a directory. The stable backend/run name is a + // grouping directory only; every artifact beneath it belongs to one run id. + args.out ??= join(stackBenchResultsRoot(ROOT), runDir, runId); + if (!args.out) throw new Error('benchmark run has no results directory'); + const outputDir = args.out; + mkdirSync(args.out, { recursive: true }); + if (existsSync(join(args.out, ARTIFACT_FILE.run))) { + throw new Error(`refusing to reuse result directory containing ${ARTIFACT_FILE.run}: ${args.out}`); + } + + // Validate caller-owned source before acquiring a backend slot so a bad + // fixture cannot leave leased resources behind. + const ownWorkDir = !args.app; + const appDir = args.app ?? join(workDirFor(track, args.backend, args.runIndex, runId), 'app'); + if (args.app) mkdirSync(appDir, { recursive: true }); + privateGradingDirectory(appDir, join(outputDir, 'grading')); + if (args.repairGrant && url.startsWith('file:')) { + url = pathToFileURL(join(appDir, 'index.html')).href; + } + + // Bind destructive and lifecycle operations to exact resource identities and + // an ownership token. Targets come only from the lease, never generated code. + const runtimeRoot = resolve(process.env.STACK_BENCH_RUNTIME_DIR + ?? join(tmpdir(), 'stack-bench-runtime')); + const runtimeDir = join(runtimeRoot, runId); + const leasePath = join(runtimeDir, ARTIFACT_FILE.backendLease); + const preparedLease = stackAdapter.lease.prepare({ + track, + runIndex: args.runIndex, + runtimeDir, + serverUri: stackRuntime.lease.serverUri, + env: process.env, + helpers: { containerIdentity: runningContainerIdentity, dbName, moduleName }, + }); + const initialLease = createBackendLease({ + runId, + backend: args.backend, + track: args.track, + runIndex: args.runIndex, + ...preparedLease.lease, + }); + const lockScope = resourceLockScope(); + const lockKeys = backendResourceLockKeys(initialLease, assignedPorts, + [...preparedLease.lockKeys, ...(args.app ? [`workspace:${realpathSync(appDir)}`] : [])]); + let privateSupervisorStatePath = null; + try { + if ((args.campaignFile || args.campaignAdmissionId) && args.backend !== 'stub') { + const executionId = process.env.STACK_BENCH_CAMPAIGN_EXECUTION; + if (!executionId || !args.experimentIdentity || !args.campaignAdmissionId + || !borrowCampaignReservation({ env: process.env, + campaignSha256: args.experimentIdentity.sha256, admissionId: args.campaignAdmissionId, + executionId, output: resolve(outputDir), leasePath, lease: initialLease, keys: lockKeys })) { + throw new Error('campaign worker requires private resource delegation'); + } + } else { + await claimBackendResourcesWhenAvailable(leasePath, initialLease, { ...lockScope, keys: lockKeys }); + } + const supervisorState = process.env.STACK_BENCH_SUPERVISOR_STATE + ?? (process.env.STACK_BENCH_SUPERVISOR_DIR + ? join(resolve(process.env.STACK_BENCH_SUPERVISOR_DIR), `${runId}.json`) : null); + if (supervisorState) { + // Private handoff to an outer timeout supervisor. It contains the lease + // token, so create it once with owner-only permissions and never place it + // in the results tree. + privateSupervisorStatePath = resolve(supervisorState); + mkdirSync(dirname(privateSupervisorStatePath), { recursive: true, mode: 0o700 }); + writeFileSync(privateSupervisorStatePath, `${JSON.stringify({ + version: SUPERVISOR_STATE_VERSION, runId, backend: args.backend, runtimeDir, leasePath, + ownershipToken: initialLease.ownershipToken, output: resolve(args.out), + })}\n`, { flag: 'wx', mode: 0o600 }); + } + } catch (error) { + if (existsSync(leasePath)) { + releaseBackendLease(leasePath, initialLease.ownershipToken); + if (!initialLease.campaignDelegation) rmSync(runtimeDir, { recursive: true, force: true }); + } + throw error; + } + process.env.STACK_BENCH_LEASE = leasePath; + process.env.STACK_BENCH_LEASE_TOKEN = initialLease.ownershipToken; + const auditNetwork = () => auditsTranscripts ? runAuditNetworkContext(track, { backend: stackAdapter.id, runIndex: args.runIndex }, + readBackendLease(leasePath, { token: initialLease.ownershipToken, backend: args.backend, runId })) + : { ownEndpoints: [], isolatedLoopback: false }; + + if (process.platform === 'win32') { + // When Windows resolves `bash` through WSL, WSLENV must carry lease paths + // and tokens into lifecycle scripts with path translation. + const bridge = ['STACK_BENCH_LEASE/p', 'STACK_BENCH_LEASE_TOKEN', + 'STACK_BENCH_NODE_BIN', ...stackRuntime.windowsEnvironmentBridge]; + const existing = (process.env.WSLENV ?? '').split(':').filter(Boolean); + process.env.WSLENV = [...new Set([...existing, ...bridge])].join(':'); + } + + let tornDown = false; + let activeRun: BenchmarkRunRecord | null = null; + const recoveryPath = join(outputDir, ARTIFACT_FILE.recovery); + const writeLeaseEvidence = (knownLease: BackendLease | null = null) => { + const lease = knownLease ?? readBackendLease(leasePath, + { token: initialLease.ownershipToken, backend: args.backend, runId }); + const out = join(outputDir, ARTIFACT_FILE.backendLease); + const evidence = publicBackendLease(lease); + const id = `${runId}-backend-lease`; + writeArtifact(out, { + kind: 'backend_lease_evidence', id, + attempt: { id, parentId: runId }, + timestamps: { startedAt: evidence.createdAt, completedAt: new Date().toISOString() }, + identities: emptyArtifactIdentities({ stackAdapter: { id: args.backend } }), + payload: evidence, + }); + return evidence; + }; + const teardown = ({ reason = null, retainBackend = args.retainBackend }: + { reason?: string | null; retainBackend?: boolean } = {}) => { + if (tornDown) return; + activeAgentCancellation?.abort(); + activeAgentCancellation = null; + // Preserve restart failures before removing the only filesystem that holds + // their stderr. A 500 after restart is otherwise impossible to distinguish + // from an application defect, a dead dependency, or host pressure. + if (activeRun) { + try { + activeRun.backendDiagnostics = captureApplicationDiagnostics(join(outputDir, 'backend.log')); + } catch (error) { + activeRun.backendDiagnostics = { captured: false, + reason: errorMessage(error).split(/\r?\n/)[0] }; + } + } + let released = false; + let cleanupError: unknown = null; + try { + released = releaseBackendLease(leasePath, initialLease.ownershipToken, + { retainBackend }); + } catch (error) { cleanupError = error; } + let finalLease = initialLease; + try { + finalLease = readBackendLease(leasePath, + { token: initialLease.ownershipToken, backend: args.backend, runId }); + } catch (error) { cleanupError ??= error; released = false; } + const evidence = writeLeaseEvidence(finalLease); + writeRecoveryArtifact(recoveryPath, finalLease, { cleanupSucceeded: released, + retained: Boolean(retainBackend), + reason: cleanupError === null ? reason ?? (released ? null : 'authenticated cleanup refused') + : errorMessage(cleanupError) }); + if (activeRun) { + activeRun.backendLease = evidence; + activeRun.outcome ??= aggregateRunOutcome(activeRun.levels); + persistRun(join(outputDir, ARTIFACT_FILE.run), activeRun); + } + tornDown = released; + if (released && !retainBackend && !finalLease.campaignDelegation) { + rmSync(runtimeDir, { recursive: true, force: true }); + if (privateSupervisorStatePath) rmSync(privateSupervisorStatePath, { force: true }); + } + if (cleanupError) throw cleanupError; + if (!released) throw new Error(`backend teardown refused: listener no longer matches lease ${runId}`); + }; + emergencyTeardown = teardown; + + try { + performPreflight(); + stackAdapter.lifecycle.activate({ + leasePath, leaseToken: initialLease.ownershipToken, lease: initialLease, + ports: assignedPorts, + ...stackRuntime.lifecycle, + }); + performPreflight(true); + } catch (error) { + try { teardown({ reason: `backend activation failed: ${errorMessage(error)}`, retainBackend: false }); } + catch (cleanupError) { + console.error(` activation cleanup quarantined: ${errorMessage(cleanupError).split(/\r?\n/)[0]}`); + } + throw error; + } + + // Teardown stops only resources recorded in this run's lease. + const interrupt = (signal: NodeJS.Signals, exitCode: number) => { + console.log(`interrupted by ${signal} — stopping exact owned resources`); + try { teardown({ reason: `interrupted by ${signal}` }); } + catch (error) { console.error(` cleanup quarantined: ${errorMessage(error).split(/\r?\n/)[0]}`); } + process.exit(exitCode); + }; + process.on('SIGINT', () => interrupt('SIGINT', 130)); + process.on('SIGTERM', () => interrupt('SIGTERM', 143)); + process.on('exit', () => { + if (!tornDown) { + try { teardown(); } catch (error) { + console.error(` cleanup failed: ${errorMessage(error).split('\n')[0]}`); + } + } + }); + + // Seed source only; the upgrade session installs its own dependencies. + if (args.seedFrom) { + const from = resolve(args.seedFrom); + if (!existsSync(from)) { console.error(`--seed-from path does not exist: ${from}`); process.exit(2); } + seedAppSource(from, appDir); + if (args.progressionSeed) { + const seeded = hashAppSource(appDir); + if (seeded.sha256 !== args.progressionSeed.sourceSha256 + || seeded.files.length !== args.progressionSeed.sourceFiles) { + throw new Error('extension source does not match its recorded identity'); + } + } + console.log(args.repairGrant + ? ` restored L${args.levelList[0]} checkpoint from ${from} for a bounded repair continuation` + : ` seeded from ${from} — level ${args.levelList[0]} will UPGRADE it, not rebuild`); + } + + if (regrade) { + const startedAt = new Date().toISOString(); + let bundle: GradeBundlePayload | null = null; + let failure: string | null = null; + let diagnostics: unknown = null; + let cleanupFailure: unknown = null; + try { + seedAppSource(regrade.sourcePath, appDir); + // prepare-only owns the container but never invokes an agent or broker. + writeFileSync(join(dirname(appDir), '.stack-bench-isolation'), 'container'); + writeFileSync(join(dirname(appDir), '.stack-bench-backend'), args.backend); + sh(process.execPath, [compiledEntrypoint('container', 'run-build.js'), '--app', appDir, + '--backend', args.backend, '--image', process.env.STACK_BENCH_IMAGE!, + '--ports', [assignedPorts.vite, assignedPorts.express].filter(Boolean).join(','), '--prepare-only'], + { stdio: 'inherit', timeout: COMMAND_TIMEOUT_MS }); + const copiedSource = hashAppSource(appDir); + if (copiedSource.sha256 !== regrade.source.sha256 || copiedSource.files.length !== regrade.source.files) { + throw new Error('regrade source changed during preparation'); + } + await materializeAcceptedSource(regrade.sourcePath, appDir, restartSpecFor(args, appDir, track)); + bundle = grade(args, appDir, url, `${args.backend}-regrade`, regrade.declared.level, + track, runId, { out: join(outputDir, 'grading'), sourceSha256: regrade.source.sha256 }); + if (!bundle || bundle.source?.sha256 !== regrade.source.sha256) { + throw new Error('regrade produced no matching source-bound grade bundle'); + } + if (hashAppSource(appDir).sha256 !== regrade.source.sha256) { + throw new Error('application source changed during regrading'); + } + } catch (error) { + failure = errorMessage(error); + if (object(error) && typeof error.startLog === 'string') { + writeFileSync(join(outputDir, 'application-start.log'), error.startLog); + } + throw error; + } finally { + try { diagnostics = captureApplicationDiagnostics(join(outputDir, 'backend.log')); } + catch (error) { diagnostics = { captured: false, reason: errorMessage(error) }; } + try { teardown({ reason: failure, retainBackend: false }); } + catch (error) { failure ??= errorMessage(error); cleanupFailure = error; } + finally { + writeFileSync(join(outputDir, 'regrade.json'), JSON.stringify({ schemaVersion: 1, + kind: 'saved-source-regrade', diagnosticOnly: true, + id: runId, startedAt, completedAt: new Date().toISOString(), + parent: { id: regrade.parent.id, runSha256: regrade.runSha256, + completedAt: regrade.parent.timestamps.completedAt, + engine: regrade.parent.identities.engine, source: regrade.source, + serverUri: regrade.serverUri, + selectionSha256: regrade.declared.selection.sha256, + recipe: regrade.declared.recipe, task: regrade.declared.task, + mode: regrade.parent.payload.mode, outcome: regrade.parent.payload.outcome, + candidate: regrade.candidate }, + engine: currentEngineIdentity(), buildImage: process.env.STACK_BENCH_IMAGE, + controllerImage: process.env.STACK_BENCH_CONTROLLER_IMAGE_ID, + dependencyVolume: process.env.STACK_BENCH_RELEASE_DEPS_VOLUME, + backend: args.backend, track: args.track, level: regrade.declared.level, + recipe: args.recipeTasks.get(regrade.declared.level)!.request.recipe, + task: args.recipeTasks.get(regrade.declared.level)!.request.task, + selectionSha256: args.recipeTasks.get(regrade.declared.level)!.selection.sha256, + selectedChecks: checksForGrade(args.recipeTasks.get(regrade.declared.level), 'scored') + .map(check => check.stableKey), + grading: bundle ? 'grading/bundle.json' : null, + gradingSha256: bundle ? sha256(readFileSync(join(outputDir, 'grading', 'bundle.json'))) : null, + outcome: bundle ? classifyBundle(bundle) : null, failure, diagnostics, + cleanupSucceeded: tornDown, + modelCalls: 0, additionalModelCostUsd: 0, + comparisonNote: regrade.dependency + ? 'Dependency first-build diagnostic; not terminal completion, a new build, or a replacement for the original outcome or spend.' + : 'Regrades the original saved app; not an independent build or a replacement for its model cost.' }, null, 2) + '\n', + { flag: 'wx' }); + if (tornDown && ownWorkDir) rmSync(dirname(appDir), { recursive: true, force: true }); + } + } + if (cleanupFailure) throw cleanupFailure; + console.log(`Saved-source regrade: ${classifyBundle(bundle).kind}; evidence ${outputDir}`); + process.exitCode = runExitCode(classifyBundle(bundle)); + return; + } + const started = Date.now(); + const run: BenchmarkRunRecord = { id: runId, + ...(args.repairGrant ? { kind: 'repair_continuation', + continuation: structuredClone(args.repairGrant.grant) } : {}), + startedAt: new Date(started).toISOString(), + parentAttemptId: args.parentAttemptId ?? null, + identities: emptyArtifactIdentities({ + experiment: args.experimentIdentity ?? null, + agentAdapter: agentAdapterIdentity(agentAdapter), + stackAdapter: { id: stackAdapter.id, version: stackAdapter.version }, + }), + mode: args.runMode ?? { id: args.progression ? 'dependency' : 'sequential' }, + track: args.track, backend: args.backend, model: args.model, + ...(args.providerRoute ? { providerRoute: args.providerRoute } : {}), + ...(args.maxOutputTokens ? { maxOutputTokens: args.maxOutputTokens } : {}), + pricing: args.pricing, + guidance: args.guidance, condition: args.condition ?? null, + ...(args.productionQuality && agentAdapter.provider ? { productionQuality: true } : {}), + skills: args.skills ?? [], + runtime: { buildImage: process.env.STACK_BENCH_IMAGE ?? DEFAULT_BUILD_IMAGE, url }, + selectionRequest: args.selectionRequest, + featureCatalog: args.featureCatalog?.identity ?? null, + dependencyPolicy: args.dependencyPolicy?.identity ?? null, + ...(args.progressionOwner ? { progressionOwner: args.progressionOwner } : {}), + ...(args.progressionSeed ? { progressionSeed: { + fromDepth: args.progressionSeed.fromDepth, + sourceSha256: args.progressionSeed.sourceSha256, + sourceFiles: args.progressionSeed.sourceFiles, + parent: structuredClone(args.progressionSeed.parent), + validatedDepths: [], + } } : {}), + backendLease: publicBackendLease(readBackendLease(leasePath, + { token: initialLease.ownershipToken, backend: args.backend, runId })), + validation: { + ladder: { policy: args.progression ? args.progression.identity.policy : 'pass-before-next-level', + requestedLevels: [...args.levelList], + completedLevels: [], stoppedAfterLevel: null, blockedLevels: [] } }, levels: [] }; + activeRun = run; + + const progressionOwner = args.progression ? { + ...args.progressionOwner, + workspace: { appDirectory: 'source' }, + } : null; + const progressionExecution = args.progression ? createLiveProgressionExecution({ + progression: args.progression, + featureCatalogIdentity: args.featureCatalog?.identity, + dependencyPolicyIdentity: args.dependencyPolicy?.identity, + owner: progressionOwner, + statePath: join(args.out, ARTIFACT_FILE.progressionState), + runId, + outputDir: args.out, + appDir, + track: args.track, + backend: args.backend, + identities: run.identities, + recipeBindings: args.recipeBindings, + retainPriorContracts: args.retainPriorContracts ?? true, + resumeFrom: args.progressionResumeFrom ?? null, + getRunArtifact: () => { + persistRun(join(outputDir, ARTIFACT_FILE.run), run); + return readArtifact(join(outputDir, ARTIFACT_FILE.run)); + }, + onState: status => { + run.progressionStatus = status; + persistRun(join(outputDir, ARTIFACT_FILE.run), run); + }, + }) : null; + const progressionStart = progressionExecution?.initialize() ?? null; + if (progressionStart?.resumed) { + const prior = progressionStart.priorRun; + if (!prior) throw new Error('resumed dependency progression has no prior run artifact'); + const actionLevel = progressionStart.action.type === 'terminal' + ? Number.MAX_SAFE_INTEGER : progressionStart.action.level; + const inheritedLevels = (prior.payload.levels ?? []) + .filter(level => level.level < actionLevel).map(level => level.level); + run.levels = (prior.payload.levels ?? []) + .filter(level => inheritedLevels.includes(level.level)).map(level => structuredClone(level)); + run.validation.ladder.completedLevels = [...inheritedLevels]; + run.progressionResume = { + priorRunId: prior.id, + priorRunSha256: sha256(canonicalDefinitionJson(prior)), + stateSha256: progressionStart.stateSha256, + action: progressionStart.action.type === 'terminal' + ? { type: 'terminal' } + : { type: progressionStart.action.type, level: progressionStart.action.level }, + inheritedLevels, + priorTotals: prior.payload.totals ?? null, + }; + run.progressionStatus = progressionStart.status; + persistRun(join(args.out, ARTIFACT_FILE.run), run); + } + + const bindProgressionAction = (level: number): ProgressionRecipeAction | null => { + if (!progressionExecution) return null; + const selected = progressionExecution.bind(level); + if (!isProgressionWorkRecipeAction(selected)) return selected; + if (!args.recipeTasks) throw new Error('recipe task map is unavailable'); + args.recipeTasks.set(level, { + request: selected.grader.request, + selection: selected.grader.selection, + task: selected.grader.task, + agentRequest: selected.agent.request, + progressionAction: selected.action, + }); + return selected; + }; + + const progressionBundles = new Map(); + const recordProgressionGrade = (input: Parameters['record']>[0]) => { + const next = progressionExecution?.record(input) ?? null; + const last = progressionExecution?.state?.attempts.at(-1) ?? null; + if (input.bundle && input.selected && isProgressionWorkRecipeAction(input.selected) + && last?.outcome === 'conclusive') { + progressionBundles.set(input.level, input.bundle as GradeBundlePayload); + } + return next; + }; + + const appendLevelRecord = (record: RunLevelRecord): void => { + pendingLevel = null; + if (args.dependencyPolicy?.definition.workSelection !== 'feature') { + run.levels.push(record); + return; + } + const index = run.levels.findIndex(candidate => candidate.level === record.level); + if (index < 0) run.levels.push(record); + else run.levels[index] = mergeFeatureLevelRecord(run.levels[index] ?? null, record); + }; + + const runAgentForLevel = async (mode: AgentMode, level: number, + onFailure?: () => Promise): Promise => { + try { + clearPrivateGradingEvidence(appDir); + pendingLevel ??= { level, graded: false, score: null, max: null, selection: null, + outcome: { kind: 'ungraded' }, buildSessions: [], repairSessions: [] }; + sessionInFlight = true; + persistRun(join(outputDir, ARTIFACT_FILE.run), run); + const result = await runAgent(args, agentAdapter, mode, level, appDir); + sessionInFlight = false; + const paid = runSessionRecord(result); + if (mode === 'fix') { + pendingLevel.repairSessions!.push(paid); + pendingLevel.repairCostUsd = addCostUsd(pendingLevel.repairCostUsd, paid.costUsd); + pendingLevel.repairs = (pendingLevel.repairs ?? 0) + 1; + } else if (mode === 'resume') { + pendingLevel.resumeSession = paid; + pendingLevel.resumeCostUsd = paid.costUsd; + } else { + pendingLevel.buildSessions!.push(paid); + pendingLevel.buildCostUsd = addCostUsd(pendingLevel.buildCostUsd, paid.costUsd); + } + pendingLevel.costUsd = addCostUsd(pendingLevel.buildCostUsd, pendingLevel.resumeCostUsd, + pendingLevel.repairCostUsd); + pendingLevel.sessionTotals = summarizeSessions([...pendingLevel.buildSessions!, + ...(pendingLevel.resumeSession ? [pendingLevel.resumeSession] : []), ...pendingLevel.repairSessions!]); + if (result.costComplete !== true) runCostComplete = false; + persistRun(join(outputDir, ARTIFACT_FILE.run), run); + return result; + } catch (error) { + await onFailure?.(); + const reason = errorMessage(error).split(/\r?\n/)[0] ?? 'agent execution failed'; + run.outcome = { kind: 'harness_failure', phase: `agent-${mode}`, + reason, appFailures: [], inconclusive: [], harnessFailures: [reason] }; + run.validation.ladder.stoppedAfterLevel = run.levels.at(-1)?.level ?? null; + run.validation.ladder.blockedLevels = args.levelList.filter(candidate => candidate >= level); + if (progressionExecution) { + recordProgressionGrade({ selected: progressionExecution.bind(level), bundle: null, level, + failure: progressionFailure(run.outcome) }); + run.progressionStatus = progressionExecution.status(); + synchronizeProgressionSummary(run, requireProgressionState(progressionExecution.state)); + } + finalizeRunTotals(run, started, { costComplete: false }); + run.completedAt = new Date().toISOString(); + persistRun(join(outputDir, ARTIFACT_FILE.run), run); + throw error; + } + }; + + // Stop before grading if a coding session read protected material or if the + // audit itself failed. Keep the paid session and exact cost in the run artifact even + // though no score may be used. + const abortUnusableSession = (whichSession: string, audit: ContaminationAudit, + levelRecord: UnknownRecord & { level: number }, + selected: ProgressionRecipeAction | null, completedRepair = false) => { + const reason = audit.evidence.join('; '); + const outcome: RunOutcome = { kind: audit.kind === 'harness_failure' ? 'harness_failure' : 'ungraded', + phase: 'contamination-audit', reason, + appFailures: [], inconclusive: [], + harnessFailures: audit.kind === 'harness_failure' ? [reason] : [] }; + run.contaminated = audit.kind === 'contaminated'; + run.contamination = { evidence: audit.evidence, verdict: audit.verdict, + detectedAt: whichSession }; + const record: RunLevelRecord = { ...levelRecord, error: reason, outcome, + level: levelRecord.level, graded: false, score: null, max: null, selection: null }; + appendLevelRecord(record); + if (progressionExecution) { + recordProgressionGrade({ selected, bundle: null, level: levelRecord.level, + failure: progressionFailure(outcome), + completedRepair }); + run.progressionStatus = progressionExecution!.status(); + synchronizeProgressionSummary(run, requireProgressionState(progressionExecution.state)); + } + run.validation.ladder.stoppedAfterLevel = run.levels.at(-2)?.level ?? null; + run.validation.ladder.blockedLevels = args.levelList + .filter(candidate => candidate >= levelRecord.level); + finalizeRunTotals(run, started, { costComplete: runCostComplete }); + run.outcome = outcome; + run.completedAt = new Date().toISOString(); + if (run.contaminated) { + console.log(`\n CONTAMINATED at ${whichSession}:`); + for (const evidence of audit.evidence) console.log(` ${evidence}`); + console.log(' Scores from this run must not be quoted.'); + } else { + console.log(`\n HARNESS FAILURE at ${whichSession}:`); + for (const evidence of audit.evidence) console.log(` ${evidence}`); + console.log(' The audit did not establish a usable result.'); + } + try { persistRun(join(outputDir, ARTIFACT_FILE.run), run); } catch { /* best effort */ } + try { archiveTranscripts(appDir, artifactLabel); } catch { /* best effort */ } + teardown(); + process.exit(4); + }; + + for (let levelIndex = 0; levelIndex < args.levelList.length; levelIndex += 1) { + const pauseDepth = args.pauseAfterDepth; + const activeState = progressionExecution?.state; + if (pauseDepth !== undefined && run.pausedDurationMs === undefined + && activeState?.phase === 'active' && activeState.level > pauseDepth + && run.levels.some(record => record.level === pauseDepth)) { + const context = readDepthPauseContext(); + if (!context || context.depth !== pauseDepth) throw new Error('planned depth pause has no controller authority'); + finalizeRunTotals(run, started, { costComplete: runCostComplete }); + persistRun(join(outputDir, ARTIFACT_FILE.run), run); + run.pausedDurationMs = await waitAtDepthBoundary(outputDir, appDir, context); + finalizeRunTotals(run, started, { costComplete: runCostComplete }); + persistRun(join(outputDir, ARTIFACT_FILE.run), run); + } + // A previous checkpoint cannot cover a newer session or partial grade. + clearTimeContinuationBoundary(outputDir); + const level = args.levelList[levelIndex]!; + const t0 = Date.now(); + const continuing = Boolean(args.repairGrant); + console.log(`\n================ ${args.backend} — level ${level} ================`); + + let progressionSelection = bindProgressionAction(level); + if (progressionSelection?.action.type === 'terminal') break; + if (args.dependencyPolicy?.definition.workSelection === 'all-at-once' + && progressionSelection?.action.level !== level) continue; + const applicationControl = materializeCodingOutput + ? restartSpecFor(args, appDir, track) : null; + const featureActionSequence = args.dependencyPolicy?.definition.workSelection === 'feature' + ? requireProgressionState(progressionExecution?.state ?? null).attempts.length + 1 : null; + const featureActionSuffix = featureActionSequence === null + ? '' : `-action${String(featureActionSequence).padStart(3, '0')}`; + // A clean-source start that fails voids a grade. Its launch log is the + // only account of why, so it stays beside the run. + const keepStartLog = (error: unknown, label: string): void => { + const startLog = error !== null && typeof error === 'object' && 'startLog' in error + ? error.startLog : null; + if (typeof startLog !== 'string' || !startLog) return; + writeFileSync(join(outputDir, `${label}-start.log`), `${startLog}\n`); + }; + const restoreFeatureAcceptedSource = async (resetDatabase = true): Promise => { + if (featureActionSequence === null) return; + const source = join(outputDir, 'source'); + try { + if (applicationControl) { + const restore = resetDatabase ? restoreRepairSource : materializeAcceptedSource; + await restore(source, appDir, applicationControl); + } else resetAppToSource(source, appDir); + } catch (error) { + console.log(` accepted feature restore failed: ${errorMessage(error)}`); + try { keepStartLog(error, `${args.backend}-l${level}${featureActionSuffix}-feature-restore`); } + catch (logError) { console.log(` could not preserve start log: ${errorMessage(logError)}`); } + // Failed coding/grading callers must still finalize their original evidence. + // The durable accepted source remains in outputDir even if local restore fails. + try { resetAppToSource(source, appDir); } + catch (restoreError) { console.log(` source restore failed: ${errorMessage(restoreError)}`); } + } + }; + if (featureActionSequence !== null && progressionSelection + && isProgressionWorkRecipeAction(progressionSelection) + && !featureActionNeedsCoding(progressionSelection, + requireProgressionState(progressionExecution?.state ?? null))) { + await restoreFeatureAcceptedSource(false); + const bundle = grade(args, appDir, url, + `${args.backend}-l${level}${featureActionSuffix}-regrade`, level, track, runId); + const outcome = classifyBundle(bundle); + const repair = { status: levelGradeIsUsable(outcome) ? 'not-needed' as const : 'ungraded' as const, + limit: 0, used: 0, stopReason: 'accepted-source-regrade' }; + let next = recordProgressionGrade({ selected: progressionSelection, bundle, + level }); + let finalOutcome = outcome; + const currentState = requireProgressionState(progressionExecution?.state ?? null); + if (next?.type === 'build' && next.level === level + && !featureActionNeedsCoding(progressionSelection, currentState)) { + const reason = 'accepted source still has ungraded checks after regrade'; + finalOutcome = { kind: 'harness_failure', phase: 'feature-regrade', reason, + appFailures: [], inconclusive: [], harnessFailures: [reason] }; + next = recordProgressionGrade({ selected: progressionSelection, bundle: null, + level, failure: progressionFailure(finalOutcome) }); + } + const state = requireProgressionState(progressionExecution?.state ?? null); + const graded = levelGradeIsUsable(finalOutcome) + && state.attempts.at(-1)?.outcome === 'conclusive'; + let checkpoint = null; + if (graded && (state.phase === 'terminal' || state.level > level)) { + checkpoint = preserveLevelCheckpoint({ appDir, outputDir, runId, + identities: run.identities, track: args.track, backend: args.backend, level, + repair, outcome: finalOutcome, + selectionSha256: bundle?.selection?.sha256 ?? null }); + } + appendLevelRecord({ level, graded, + score: graded ? bundle?.totals?.score ?? null : null, + max: graded ? bundle?.totals?.max ?? null : null, + selection: graded ? bundle?.selection ?? null : null, + regression: bundle?.totals?.regression ?? null, + contractPass: bundle?.totals?.contractPass ?? null, + code: bundle?.code ?? null, + repair, + checkpoint, + sessionTotals: summarizeSessions([]), + costUsd: 0, + repairs: 0, + durationSec: Math.round((Date.now() - t0) / 1000), + outcome: finalOutcome }); + if (graded && (state.phase === 'terminal' || state.level > level) + && !run.validation.ladder.completedLevels.includes(level)) { + run.validation.ladder.completedLevels.push(level); + } + run.progressionStatus = progressionExecution!.status(); + persistRun(join(outputDir, ARTIFACT_FILE.run), run); + if (state.phase === 'terminal') break; + if (state.attempts.at(-1)?.outcome === 'inconclusive') { + run.validation.ladder.stoppedAfterLevel = level; + run.validation.ladder.blockedLevels = args.levelList.filter(candidate => candidate >= level); + break; + } + if (next?.type !== 'terminal' && next?.level === level) { + levelIndex -= 1; + continue; + } + if (next?.type !== 'terminal' && next && next.level < level) { + throw new Error(`dependency progression moved backward from L${level}`); + } + continue; + } + if (args.seedThrough !== undefined && level <= args.seedThrough) { + if (!progressionSelection || !isProgressionWorkRecipeAction(progressionSelection) + || progressionSelection.action.level !== level || !args.seedFrom || !run.progressionSeed) { + throw new Error(`extension cannot validate depth ${level}`); + } + let applicationFailure: RunOutcome | null = null; + if (applicationControl) { + try { + await materializeAcceptedSource(args.seedFrom, appDir, applicationControl); + } catch (error) { + applicationFailure = materializationAppFailure(error); + keepStartLog(error, `${args.backend}-extension-l${level}`); + } + } else { + resetAppToSource(args.seedFrom, appDir); + } + const bundle = grade(args, appDir, url, `${args.backend}-extension-l${level}`, + level, track, runId, { applicationFailure }); + const outcome = applicationFailure ?? classifyBundle(bundle); + const next = recordProgressionGrade({ selected: progressionSelection, bundle, level }); + const progressionState = requireProgressionState(progressionExecution?.state ?? null); + const progressionAttempt = progressionState.attempts.at(-1) ?? null; + const graded = levelGradeIsUsable(outcome, progressionAttempt); + const passed = graded && outcome.kind === 'passed'; + const repair = { status: passed ? 'not-needed' as const : 'incomplete' as const, + limit: 0, used: 0, + stopReason: passed ? 'not-needed' : 'extension-validation-failed' }; + let checkpoint = null; + try { + checkpoint = preserveLevelCheckpoint({ appDir, outputDir: args.out, runId, + identities: run.identities, track: args.track, backend: args.backend, level, + repair, outcome, selectionSha256: bundle?.selection?.sha256 ?? null }); + } catch (error) { + throw new Error(`could not preserve extension depth ${level}: ${errorMessage(error)}`); + } + const source = hashAppSource(appDir); + appendLevelRecord({ level, graded, + score: graded ? bundle?.totals?.score ?? null : null, + max: graded ? bundle?.totals?.max ?? null : null, + selection: bundle?.selection ?? null, + baseline: { kind: 'extension-validation', source: { + sha256: source.sha256, files: source.files.length } }, + regression: bundle?.totals?.regression ?? null, + contractPass: bundle?.totals?.contractPass ?? null, + code: bundle?.code ?? null, + repair, + checkpoint, + sessionTotals: summarizeSessions([]), + costUsd: 0, + repairs: 0, + durationSec: Math.round((Date.now() - t0) / 1000), + outcome }); + if (progressionAttempt?.outcome === 'conclusive') { + if (!run.validation.ladder.completedLevels.includes(level)) { + run.validation.ladder.completedLevels.push(level); + } + } + run.progressionStatus = progressionExecution!.status(); + if (passed) run.progressionSeed.validatedDepths.push(level); + if (!passed) { + run.validation.ladder.stoppedAfterLevel = level > 1 ? level - 1 : null; + run.validation.ladder.blockedLevels = args.levelList.filter(candidate => candidate >= level); + persistRun(join(args.out, ARTIFACT_FILE.run), run); + break; + } + persistRun(join(args.out, ARTIFACT_FILE.run), run); + if (!next || next.type === 'terminal' || next.level === undefined || next.level <= level) { + throw new Error(`extension did not advance after depth ${level}`); + } + continue; + } + const resumedRepair = progressionStart?.resumed === true + && progressionStart.action.type === 'repair'; + // The interrupted repair was charged but never graded. Grade its preserved + // source before any coding session. + const resumedGrade = resumedRepair && progressionStart?.action.type === 'repair' + && progressionStart.action.repair.awaitingGrade === true; + const resumedRegression = resumedRepair + ? savedRepairRegression(progressionExecution?.state ?? null, progressionSelection) : null; + const resumedRegressionReport = resumedRegression + ? join(args.out, 'repair-reports', + `rejected-regression-l${level}${featureActionSuffix}-resume.md`) : null; + const priorRepairs = resumedRepair + ? progressionStart.priorRun?.payload.levels?.find(item => item.level === level) + ?.repair?.used ?? 0 + : args.progression ? 0 : run.levels.reduce((sum, item) => sum + (item.repairs ?? 0), 0); + const repairBudgetFor = (selected: ProgressionRecipeAction | null, + completedRepairs: number) => selected + && isProgressionWorkRecipeAction(selected) + ? dependencyRepairBudget(selected.action, completedRepairs) + : args.repairs; + const levelRepairNodeIds = new Set(progressionSelection?.action.repair.nodeIds ?? []); + let progressionRepairLimit = repairBudgetFor( + progressionSelection, priorRepairs); + const trackProgressionBudget = (selected: ProgressionRecipeAction | null, + completedRepairs: number) => { + if (!selected || !isProgressionWorkRecipeAction(selected)) return; + selected.action.repair.nodeIds.forEach(nodeId => levelRepairNodeIds.add(nodeId)); + progressionRepairLimit = Math.max( + progressionRepairLimit, repairBudgetFor(selected, completedRepairs)); + }; + if (resumedRepair && !resumedGrade) { + let reportFailure: string | null = null; + try { + if (resumedRegressionReport && resumedRegression) { + mkdirSync(dirname(resumedRegressionReport), { recursive: true }); + writeFileSync(resumedRegressionReport, resumedRegression.report); + } + sh('node', [join(ROOT, 'dist', 'commands', 'report-bugs.js'), '--app', appDir, + '--history-json', '[]', '--archive', join(args.out, 'repair-reports', + `bug-report-l${level}${featureActionSuffix}-resume.md`), + ...(resumedRegressionReport ? ['--prior-regression', resumedRegressionReport] : []), + ...repairReportArgs(progressionSelection)], + { stdio: 'pipe' }); + } catch (error) { + reportFailure = errorMessage(error).split(/\r?\n/)[0] + ?? 'repair report generation failed'; + } + if (reportFailure) { + const outcome: RunOutcome = { + kind: 'harness_failure', phase: 'repair-report', reason: reportFailure, + appFailures: [], inconclusive: [], harnessFailures: [reportFailure], + }; + recordProgressionGrade({ selected: progressionSelection, bundle: null, level, + failure: progressionFailure(outcome) }); + appendLevelRecord({ level, graded: false, score: null, max: null, + selection: null, error: reportFailure, outcome, + repair: { status: 'ungraded', limit: progressionRepairLimit, + used: priorRepairs, stopReason: 'repair-report' }, + repairCostUsd: 0, repairSessions: [], repairs: 0, priorRepairs, + cumulativeRepairs: priorRepairs, sessionTotals: summarizeSessions([]), + costUsd: 0, durationSec: Math.round((Date.now() - t0) / 1000) }); + run.validation.ladder.stoppedAfterLevel = level; + run.validation.ladder.blockedLevels = args.levelList.filter(candidate => candidate >= level); + persistRun(join(args.out, ARTIFACT_FILE.run), run); + break; + } + } + + const firstMode = resumedRepair ? 'fix' + : continuing ? 'resume' : args.seedFrom ? 'upgrade' : 'build'; + const build = resumedGrade ? null : await runAgentForLevel( + resumedRepair || run.levels.length === 0 ? firstMode : 'upgrade', level, + featureActionSequence === null ? undefined : restoreFeatureAcceptedSource); + // Only a resumed grade runs a level without a coding session. + const requireBuild = (): NonNullable => { + if (!build) throw new Error(`level ${level} has no coding session`); + return build; + }; + const buildFailure = build ? agentSessionFailure(build) : null; + const buildLeak = build && !buildFailure ? auditContamination(appDir, auditNetwork(), auditsTranscripts) : null; + if (buildLeak) { + const session = requireBuild(); + const buildSession = runSessionRecord(session, + resumedRepair ? priorRepairs + 1 : null); + const sessionTotals = summarizeSessions([buildSession]); + abortUnusableSession(`level ${level} ${firstMode}`, buildLeak, { + level, graded: false, score: null, max: null, selection: null, + ...(resumedRepair + ? { repairCostUsd: session.costUsd, repairSessions: [buildSession], repairs: 1, + priorRepairs, cumulativeRepairs: priorRepairs + 1 } + : continuing + ? { resumeCostUsd: session.costUsd, resumeSession: buildSession } + : { buildCostUsd: session.costUsd, buildSessions: [buildSession] }), + sessionTotals, costUsd: session.costUsd, durationMs: Date.now() - t0, + }, progressionSelection, resumedRepair); + } + // Record the session setup needed to compare runs. + if (build) run.setup ??= build.setup; + if (continuing) { + const session = requireBuild(); + requireContinuation(run).resumeSetup = { + sessionId: session.sessionId ?? null, + costUsd: session.costUsd, + durationMs: session.durationMs, + sourceVerified: false, + }; + } + // No session, no app. Grading an empty directory yields a real-looking zero + // that is a harness failure, not a result for this backend. + if (buildFailure) { + const session = requireBuild(); + await restoreFeatureAcceptedSource(); + console.log(` ABORTED: ${buildFailure.reason}. Details will be kept in ${join(args.out, ARTIFACT_FILE.run)}`); + const failedSession = runSessionRecord(session); + if (progressionExecution) { + recordProgressionGrade({ selected: progressionSelection, bundle: null, level, + failure: buildFailure }); + } + appendLevelRecord({ level, graded: false, score: null, max: null, + selection: null, error: buildFailure.reason, + outcome: buildFailure, + ...(continuing + ? { resumeSession: failedSession, resumeCostUsd: session.costUsd } + : { buildSessions: [failedSession], buildCostUsd: session.costUsd }), + sessionTotals: summarizeSessions([session]), + costUsd: session.costUsd, durationMs: Date.now() - t0 }); + break; + } + const gradeAcceptedSource = async (sourcePath: string, + label: string): Promise => { + let failure: RunOutcome | null = null; + if (applicationControl) { + try { + await materializeAcceptedSource(sourcePath, appDir, applicationControl); + } catch (error) { + failure = materializationAppFailure(error); + keepStartLog(error, label); + } + } else { + resetAppToSource(sourcePath, appDir); + } + return grade(args, appDir, url, label, level, track, runId, + { applicationFailure: failure }); + }; + const checkpointGrade = (phase: RunCheckpoint['phase'], measured: GradeBundlePayload, + sessions: RunSessionRecord[], accepted: boolean): void => { + if (!args.condition?.requested?.levels.length || !measured.source?.sha256 + || !measured.selection?.sha256) return; + const source = join(privateGradingDirectory(appDir), ARTIFACT_FILE.gradeBundle); + const evidence = readArtifactPayload(source, { expectedKind: 'grade_bundle' }); + if (evidence.source?.sha256 !== measured.source.sha256 + || evidence.selection?.sha256 !== measured.selection.sha256) { + throw new Error('grading checkpoint does not match the current source and selection'); + } + const path = `checkpoints/${(run.checkpoints?.length ?? 0) + 1}.json`; + mkdirSync(join(outputDir, 'checkpoints'), { recursive: true }); + copyFileSync(source, join(outputDir, path)); + const prior = progressionStart?.priorRun?.payload; + const priorCheckpoint = Array.isArray(prior?.checkpoints) + ? prior.checkpoints.map(value => checkpointSchema.parse(value)).findLast(checkpoint => checkpoint.accepted) + : undefined; + const prompt = progressionSelection?.action.prompt; + recordRunCheckpoint({ ...run, condition: args.condition, checkpoints: run.checkpoints ??= [] }, + { phase, level, bundle: evidence, + sourceSha256: measured.source.sha256, + evidence: { path, sha256: sha256(readFileSync(join(outputDir, path))) }, + extraSessions: sessions, accepted, + ...(prior ? { priorCost: runCostEvidence(prior), + initialChecks: priorCheckpoint?.checks } : {}), + workNodeIds: object(prompt) && Array.isArray(prompt.nodeIds) + ? prompt.nodeIds.filter((id): id is string => typeof id === 'string') : [] }); + persistRun(join(outputDir, ARTIFACT_FILE.run), run); + }; + const restoreAcceptedRepair = async (sourcePath: string, gradingPath: string, + completedRepair = true): Promise => { + try { + try { + if (applicationControl) await restoreRepairSource(sourcePath, appDir, applicationControl); + else resetAppToSource(sourcePath, appDir); + } finally { + restorePrivateGradingEvidence(appDir, gradingPath); + } + return true; + } catch (error) { + let reason = `could not restore the accepted repair source: ${errorMessage(error)}`; + const preserved = join(outputDir, `repair-rollback-l${level}${featureActionSuffix}-round${repairs}`); + try { + snapshotSource(sourcePath, join(preserved, 'source')); + if (existsSync(gradingPath)) cpSync(gradingPath, join(preserved, 'grading'), { recursive: true }); + keepStartLog(error, `${args.backend}-l${level}${featureActionSuffix}-rollback${repairs}`); + reason += `; accepted source and available grading evidence kept at ${preserved}`; + } catch (preserveError) { + reason += `; could not preserve the accepted rollback snapshot: ${errorMessage(preserveError)}`; + } + console.log(` ${reason}; stopping repairs`); + recordRepairHarnessFailure('repair-restore', reason, null, completedRepair); + return false; + } + }; + // Keep a repaired source whose grade did not finish beside the run, bound + // by hash, so a resume can grade exactly what the paid session produced. + const preserveRepairCandidate = (directory: string): RunRepairCandidate => { + const path = join(outputDir, directory); + rmSync(path, { recursive: true, force: true }); + const live = hashAppSource(appDir); + snapshotSource(appDir, path); + const preserved = hashDirectory(path); + if (live.sha256 !== preserved.sha256 || live.files.length !== preserved.files.length) { + throw new Error('preserved repair source differs from the live application source'); + } + return { directory, sha256: preserved.sha256, files: preserved.files.length }; + }; + if (resumedGrade) { + const candidate = progressionStart?.priorRun?.payload.levels + ?.find(item => item.level === level)?.repair?.candidate; + const candidateRoot = args.progressionResumeFrom ?? outputDir; + let candidateFailure: string | null = null; + if (!candidate || !/^[A-Za-z0-9._-]+$/.test(candidate.directory) + || !existsSync(join(candidateRoot, candidate.directory))) { + candidateFailure = 'the interrupted repair left no source to grade'; + } else { + const candidatePath = join(candidateRoot, candidate.directory); + const preserved = hashDirectory(candidatePath); + if (preserved.sha256 !== candidate.sha256 + || preserved.files.length !== candidate.files) { + candidateFailure = 'the interrupted repair source does not match its record'; + } else { + resetAppToSource(candidatePath, appDir); + console.log(` restored the interrupted repair source from ${candidatePath}`); + } + } + if (candidateFailure) { + const outcome: RunOutcome = { + kind: 'harness_failure', phase: 'repair-candidate', reason: candidateFailure, + appFailures: [], inconclusive: [], harnessFailures: [candidateFailure], + }; + recordProgressionGrade({ selected: progressionSelection, bundle: null, level, + failure: progressionFailure(outcome) }); + appendLevelRecord({ level, graded: false, score: null, max: null, + selection: null, error: candidateFailure, outcome, + repair: { status: 'ungraded', limit: progressionRepairLimit, + used: priorRepairs, stopReason: 'repair-candidate' }, + repairCostUsd: 0, repairSessions: [], repairs: 0, priorRepairs, + cumulativeRepairs: priorRepairs, sessionTotals: summarizeSessions([]), + costUsd: 0, durationSec: Math.round((Date.now() - t0) / 1000) }); + run.validation.ladder.stoppedAfterLevel = level; + run.validation.ladder.blockedLevels = args.levelList.filter(candidate => candidate >= level); + persistRun(join(args.out, ARTIFACT_FILE.run), run); + break; + } + } + if (continuing) { + // A resume may restore runtime state but cannot change checkpoint source. + const resumed = hashAppSource(appDir); + const repairGrant = args.repairGrant; + if (!repairGrant) throw new Error('repair continuation has no grant'); + if (resumed.sha256 !== repairGrant.checkpoint.payload.source.sha256 + || resumed.files.length !== repairGrant.checkpoint.payload.source.files) { + throw new Error('resume setup changed the parent checkpoint source'); + } + const continuation = requireContinuation(run); + if (!continuation.resumeSetup) throw new Error('repair continuation did not record resume setup'); + continuation.resumeSetup.sourceVerified = true; + } + if (args.referenceMutationOnly) { + const session = requireBuild(); + appendLevelRecord({ level, score: null, max: null, graded: false, contractPass: null, + selection: null, + outcome: { kind: 'ungraded', phase: 'reference-mutation-only', + reason: 'the parent qualification owns the full clean grade', + appFailures: [], inconclusive: [], harnessFailures: [] }, + buildSessions: [runSessionRecord(session)], + buildCostUsd: session.costUsd, sessionTotals: summarizeSessions([session]), + costUsd: session.costUsd, durationMs: Date.now() - t0 }); + break; + } + const firstBuildDirectory = continuing + ? `baseline-l${level}${featureActionSuffix}` + : `first-build-l${level}${featureActionSuffix}`; + const firstBuildPath = join(args.out, firstBuildDirectory); + let firstBuildSource = null; + let materializationOutcome: RunOutcome | null = null; + try { + const liveSource = hashAppSource(appDir); + snapshotSource(appDir, firstBuildPath); + const preservedSource = hashDirectory(firstBuildPath); + if (liveSource.sha256 !== preservedSource.sha256) { + throw new Error('preserved first-build source differs from the live application source'); + } + firstBuildSource = { sha256: liveSource.sha256, files: liveSource.files.length }; + if (applicationControl) { + await materializeAcceptedSource(firstBuildPath, appDir, applicationControl); + } + console.log(` kept the ${continuing ? 'continuation baseline' : 'unaided'} source at ${firstBuildPath}`); + } catch (error) { + if (firstBuildSource) { + materializationOutcome = materializationAppFailure(error); + keepStartLog(error, `${args.backend}-l${level}${featureActionSuffix}`); + } + console.log(materializationOutcome + ? ` application failure: ${materializationOutcome.reason}` + : ` harness failure: could not bind the first-build source: ${errorMessage(error).split('\n')[0]}`); + } + const firstBuildLabel = `${args.backend}-l${level}${featureActionSuffix}`; + let bundle = firstBuildSource + ? await gradeWithRetry({ appDir, outputDir, label: firstBuildLabel, + archiveLabel: `l${level}${featureActionSuffix}-before-retry`, + retry: !materializationOutcome, + runGrade: label => grade(args, appDir, url, label, level, track, runId, + { applicationFailure: materializationOutcome }) }) : null; + let reusableRepairEvidence: { + bundle: GradeBundlePayload; + results: string; + } | null = null; + + // Keep the unaided result separate from the result after repairs. + const firstBuild: FirstBuildRecord = { + score: bundle?.totals?.score ?? null, + max: bundle?.totals?.max ?? null, + regression: bundle?.totals?.regression ?? null, + contractPass: bundle?.totals?.contractPass ?? null, + outcome: materializationOutcome ?? sourceBoundFirstBuildOutcome(bundle, firstBuildSource), + source: firstBuildSource, + missed: Object.values(bundle?.suites ?? {}).flatMap(s => + (s?.features ?? []).flatMap(f => + (f.criteria ?? []).filter(c => !evidencePassed(criterionEvidence(c))) + .map(c => `${f.name}/${c.id}`))), + }; + + if (continuing) { + const repairGrant = args.repairGrant; + if (!repairGrant) throw new Error('repair continuation has no grant'); + if (firstBuild.score === null || firstBuild.max === null || firstBuildSource === null) { + throw new Error('repair continuation did not produce a source-bound baseline score'); + } + const reproduction = compareRepairBaseline(repairGrant.level, { + score: firstBuild.score, + max: firstBuild.max, + selectionSha256: bundle?.selection?.sha256 ?? null, + sourceSha256: firstBuildSource.sha256, + expectedSourceSha256: repairGrant.checkpoint.payload.source.sha256, + outcome: repairOutcome(firstBuild.outcome), + }); + requireContinuation(run).baseline = { + score: firstBuild.score, + max: firstBuild.max, + selectionSha256: bundle?.selection?.sha256 ?? null, + sourceSha256: firstBuildSource?.sha256 ?? null, + outcome: firstBuild.outcome, + ...reproduction, + }; + if (!reproduction.reproduced) { + const reason = `restored checkpoint did not reproduce its parent: ${reproduction.mismatches.join(', ')}`; + console.log(` CONTINUATION STOPPED: ${reason}`); + const failure = { kind: 'harness_failure', phase: 'continuation-baseline', reason, + appFailures: [], inconclusive: [], harnessFailures: [] }; + firstBuild.outcome = failure; + bundle = { ...bundle, outcome: failure }; + } + } + + if (bundle && firstBuildSource && levelGradeIsUsable(firstBuild.outcome)) { + const accepted = !(featureActionSequence !== null && progressionSelection + && isProgressionWorkRecipeAction(progressionSelection)) + || featureCandidateAccepted(progressionSelection, + requireProgressionState(progressionExecution?.state ?? null), bundle); + checkpointGrade(resumedRepair ? 'repair' : 'first-build', bundle, + build ? [runSessionRecord(build)] : [], accepted); + } + + const selectedObservedChecks = checksForGrade(args.recipeTasks?.get(level), 'observed'); + if (!continuing && !resumedRepair && selectedObservedChecks.length) { + const observationOut = join(args.out, + `first-build-l${level}${featureActionSuffix}-observed`); + let observationBundle = null; + let observationOutcome; + if (!firstBuildSource) { + observationOutcome = { kind: 'harness_failure', phase: 'first-build-source', + reason: 'observed specifications require a source-bound first build' }; + } else if (!ladderMayContinue(firstBuild.outcome)) { + observationOutcome = { kind: 'ungraded', phase: 'first-build-observation', + reason: 'scored first-build grading did not establish a usable environment' }; + } else { + observationBundle = grade(args, appDir, url, `${args.backend}-l${level}-observed`, level, + track, runId, { observation: 'observed', out: observationOut, + sourceSha256: firstBuildSource.sha256 }); + observationOutcome = classifyBundle(observationBundle); + } + firstBuild.observations = { + sourceSha256: firstBuildSource?.sha256 ?? null, + selectionSha256: args.recipeTasks?.get(level)?.selection.sha256 ?? null, + selectedChecks: selectedObservedChecks.map(check => check.stableKey), + reportedChecks: observationBundle?.selection?.reportedChecks ?? [], + passedPoints: observationBundle?.totals?.score ?? null, + observedPoints: observationBundle?.totals?.max ?? null, + scoreContribution: false, + repairVisible: false, + artifact: observationBundle + ? `first-build-l${level}${featureActionSuffix}-observed/${ARTIFACT_FILE.gradeBundle}` : null, + outcome: observationOutcome, + }; + } + + let initialProgressionFailure: ProgressionFailure | null = null; + if (featureActionSequence !== null && progressionSelection + && isProgressionWorkRecipeAction(progressionSelection)) { + const candidateOutcome = classifyBundle(bundle); + archiveCandidateGrade(appDir, outputDir, `l${level}${featureActionSuffix}`); + if (!levelGradeIsUsable(candidateOutcome)) { + await restoreFeatureAcceptedSource(); + initialProgressionFailure = progressionFailure(candidateOutcome); + } else if (!featureCandidateAccepted(progressionSelection, + requireProgressionState(progressionExecution?.state ?? null), + bundle)) { + bundle = await gradeAcceptedSource(join(outputDir, 'source'), + `${args.backend}-l${level}${featureActionSuffix}-restored`, + ); + const restoredOutcome = classifyBundle(bundle); + if (!levelGradeIsUsable(restoredOutcome)) { + initialProgressionFailure = progressionFailure(restoredOutcome); + } + } + } + + // Preserve the first source and scored grading before repair overwrites the + // app. Observed evidence remains in its own source-bound result directory. + const acceptedGradingDirectory = continuing + ? `baseline-l${level}${featureActionSuffix}-grading` + : `first-build-l${level}${featureActionSuffix}-grading`; + try { + const gradingFrom = privateGradingDirectory(appDir); + if (existsSync(gradingFrom)) { + const gradingTo = join(args.out, acceptedGradingDirectory); + cpSync(gradingFrom, gradingTo, { + recursive: true, + filter: src => !/[\\/]media([\\/]|$)/.test(src), + }); + if (bundle) reusableRepairEvidence = { bundle, results: gradingTo }; + console.log(` kept the ${continuing ? 'continuation baseline' : 'unaided'} grading at ${join(args.out, acceptedGradingDirectory)}`); + } + } catch (e) { + // Never worth losing a run over: the score is already recorded. + console.log(` harness failure: could not keep the first build: ${errorMessage(e).split('\n')[0]}`); + } + + // A resumed grade settles a repair that was already charged; only a + // resumed coding session is a new repair. + let repairs = resumedRepair && !resumedGrade ? 1 : 0; + let repairCost = resumedRepair && build ? build.costUsd : 0; + const repairSessions = resumedRepair && build + ? [runSessionRecord(build, priorRepairs + 1)] : []; + const repairHistory: ReturnType[] = []; + let repairCandidate: RunRepairCandidate | null = null; + let priorRegressionReport = resumedRegressionReport; + let priorRegressionOwner = repairOwnerNodeIds(progressionSelection).join('\n') || null; + let regressed = false; + let repairStopReason: string | null = null; + let repairProgress = repairProgressState(null, bundle); + const pauseForRepeatedFindings = () => { + if (args.progression) return false; + repairProgress = repairProgressState(repairProgress, bundle); + if (args.maxStalledRepairs === 0 + || repairProgress.stalledRounds < args.maxStalledRepairs) return false; + repairStopReason = 'repeated-findings'; + console.log(` pausing after ${repairProgress.stalledRounds} repairs ` + + 'with the same failed checks and no score gain'); + return true; + }; + const initialBundleOutcome = classifyBundle(bundle); + const initialProgressionAttempt = args.progression + ? requireProgressionState(progressionExecution?.state ?? null).attempts.at(-1) ?? null + : null; + const initialGradeUsable = levelGradeIsUsable(initialBundleOutcome, + initialProgressionAttempt); + if (!initialGradeUsable) { + repairStopReason = 'initial-grading-failed'; + console.log(' repairs skipped: the initial grade did not complete, so there are no reliable findings to fix'); + } + + let progressionNext = recordProgressionGrade({ + selected: progressionSelection, + bundle: initialProgressionFailure ? null : bundle, + level, + failure: initialProgressionFailure, + completedRepair: resumedRepair && !resumedGrade, + }); + // Never start a paid repair with nothing left to spend or while a charged + // repair still waits for its grade. + const progressionMayRepair = () => !args.progression + || (progressionNext?.type === 'repair' && progressionNext.repair.remaining > 0 + && progressionNext.repair.awaitingGrade !== true); + // One allowance for both modes: the engine's remaining repairs in + // dependency mode, the run-wide total less every repair so far otherwise. + const repairsRemaining = (): number => args.progression + ? (progressionNext?.type === 'repair' ? progressionNext.repair.remaining : 0) + : args.repairs - priorRepairs - repairs; + const mayRepair = (): boolean => args.progression + ? progressionMayRepair() : repairsRemaining() > 0; + const recordRepairProgression = ({ failure = null, repairRegression = null, + completedRepair = false }: { + failure?: ProgressionFailure | null; + repairRegression?: ProgressionRepairRegression | null; + completedRepair?: boolean; + } = {}) => { + progressionNext = recordProgressionGrade({ + selected: progressionSelection, + bundle: failure ? null : bundle, + level, + failure, + repairRegression, + completedRepair, + }); + return progressionMayRepair(); + }; + const recordRepairHarnessFailure = (phase: string, reason: string, + failedBundle: GradeBundlePayload | null = null, completedRepair = false): void => { + const failure: RunOutcome = { + kind: 'harness_failure', phase, reason, + appFailures: [], inconclusive: [], harnessFailures: [reason], + }; + bundle = failedBundle ? { ...failedBundle, outcome: failure } : { outcome: failure }; + repairStopReason = phase; + if (args.progression) recordRepairProgression({ + failure: progressionFailure(failure), completedRepair, + }); + const failedLevel = progressionExecution?.state?.attempts.at(-1)?.level; + const prior = run.levels.find(record => record.level === failedLevel); + if (prior) prior.outcome = failure; + }; + const restoreProgressionGrade = (accepted: GradeBundlePayload | null, + label: string): boolean => { + const expected = progressionSelection && isProgressionWorkRecipeAction(progressionSelection) + ? progressionSelection.grader.selectionSha256 : null; + if (!expected || accepted?.selection?.sha256 === expected) { + bundle = accepted; + return true; + } + bundle = grade(args, appDir, url, label, level, track, runId); + const outcome = classifyBundle(bundle); + if (levelGradeIsUsable(outcome)) return true; + recordRepairHarnessFailure('repair-restore-grading', + outcome.reason ?? 'restored source did not produce a reliable grade', bundle, true); + return false; + }; + const writeRepairReport = (results: string | null = null): + { status: 0 | 3 | 4 } | { status: 'failed'; reason: string } => { + try { + sh('node', [join(ROOT, 'dist', 'commands', 'report-bugs.js'), '--app', appDir, + ...(results ? ['--results', results] : []), + '--history-json', JSON.stringify(repairHistory), + '--archive', join(outputDir, 'repair-reports', + `bug-report-l${level}${featureActionSuffix}-round${repairs + 1}.md`), + ...(priorRegressionReport ? ['--prior-regression', priorRegressionReport] : []), + ...repairReportArgs(progressionSelection)], { stdio: 'pipe' }); + return { status: 0 }; + } catch (error) { + const failure = commandFailure(error); + if (failure.status === 3 || failure.status === 4) return { status: failure.status }; + return { status: 'failed', reason: errorMessage(failure).split(/\r?\n/)[0] + ?? 'repair report generation failed' }; + } + }; + const recordMissingRepairFeedback = (status: 3 | 4): void => { + repairStopReason = 'no-actionable-findings'; + if (!args.progression) return; + const reason = status === 3 + ? 'selected repair checks contain no failures' + : 'selected repair checks produced no actionable findings'; + const failure: RunOutcome = { + kind: 'harness_failure', phase: 'repair-report', reason, + appFailures: [], inconclusive: [], harnessFailures: [reason], + }; + bundle = { outcome: failure }; + recordRepairProgression({ failure: progressionFailure(failure) }); + }; + + // Hand back findings and let the agent fix, until clean or out of rounds. + while (levelGradeIsUsable(classifyBundle(bundle), args.progression + ? requireProgressionState(progressionExecution?.state ?? null).attempts.at(-1) ?? null + : null) && mayRepair()) { + let reportReady = false; + const acceptedBundle = bundle; + let repairBaselineBundle = bundle; + if (args.progression) { + progressionSelection = bindProgressionAction(level); + const repairOwner = repairOwnerNodeIds(progressionSelection).join('\n') || null; + if (repairOwner !== priorRegressionOwner) { + priorRegressionReport = null; + priorRegressionOwner = repairOwner; + } + trackProgressionBudget(progressionSelection, priorRepairs + repairs); + if (progressionSelection && isProgressionWorkRecipeAction(progressionSelection) + && bundle?.selection?.sha256 !== progressionSelection.grader.selectionSha256) { + const sequence = requireProgressionState(progressionExecution?.state ?? null).attempts.length + 1; + const targetChecks = repairCheckKeys(progressionSelection); + const sourceSha256 = hashAppSource(appDir).sha256; + const hasCurrentTargetEvidence = bundle?.source?.sha256 === sourceSha256 + && targetChecks.every(check => bundle?.selection?.reportedChecks?.includes(check)); + const reusable = reusableRepairEvidence?.bundle.source?.sha256 === sourceSha256 + && targetChecks.every(check => + reusableRepairEvidence?.bundle.selection?.reportedChecks?.includes(check)) + ? reusableRepairEvidence : null; + let repairResults = hasCurrentTargetEvidence ? null : reusable?.results ?? null; + if (reusable && !hasCurrentTargetEvidence) repairBaselineBundle = reusable.bundle; + if (!hasCurrentTargetEvidence && !reusable) { + const binding = args.recipeBindings.get(level); + if (!binding) throw new Error(`L${level} has no recipe binding`); + const targetTask = resolveProgressionRepairTarget(binding, + requireProgressionState(progressionExecution?.state ?? null)); + repairResults = join(outputDir, 'repair-grades', + `l${level}${featureActionSuffix}-round-${repairs + 1}`); + repairBaselineBundle = grade(args, appDir, url, + `${args.backend}-l${level}-repair-target${sequence}`, + level, track, runId, { out: repairResults, recipeTask: targetTask }); + } + const refreshOutcome = classifyBundle(repairBaselineBundle); + const refreshUsable = levelGradeIsUsable(refreshOutcome); + if (!refreshUsable) { + recordRepairHarnessFailure('refresh-grading-failed', + refreshOutcome.reason ?? 'repair target did not produce a reliable grade', + repairBaselineBundle); + break; + } + const refreshReport = writeRepairReport(repairResults); + if (refreshReport.status === 'failed') { + recordRepairHarnessFailure('repair-report', refreshReport.reason); + break; + } + if (refreshReport.status === 3) { + bundle = grade(args, appDir, url, + `${args.backend}-l${level}-repair-refresh${sequence}`, + level, track, runId); + if (!levelGradeIsUsable(classifyBundle(bundle))) { + recordRepairHarnessFailure('refresh-grading-failed', + classifyBundle(bundle).reason ?? 'repair refresh did not produce a reliable grade', + bundle); + break; + } + checkpointGrade('final', bundle!, + [...(build && !resumedRepair ? [runSessionRecord(build)] : []), ...repairSessions], true); + recordRepairProgression(); + continue; + } + if (refreshReport.status === 4) { + recordMissingRepairFeedback(refreshReport.status); + break; + } + reportReady = true; + } + } + const report = reportReady ? { status: 0 as const } : writeRepairReport(); + if (report.status === 'failed') { + recordRepairHarnessFailure('repair-report', report.reason); + break; + } + if (report.status !== 0) { + recordMissingRepairFeedback(report.status); + break; + } + + const before = repairBaselineBundle?.totals?.score ?? 0; + const beforeMax = repairBaselineBundle?.totals?.max ?? 0; + const beforeBundle = repairBaselineBundle; + // Keep the accepted source outside paths visible to the coding session. + const snapshot = join(tmpdir(), `stack-bench-snapshot-${args.backend}-${args.track}-run${args.runIndex}-l${level}`); + const gradingSnapshot = `${snapshot}-grading`; + const acceptedSource = hashAppSource(appDir); + snapshotSource(appDir, snapshot); + rmSync(gradingSnapshot, { recursive: true, force: true }); + if (existsSync(privateGradingDirectory(appDir))) { + cpSync(privateGradingDirectory(appDir), gradingSnapshot, { recursive: true }); + } + const cleanupRepairSnapshots = () => { + rmSync(snapshot, { recursive: true, force: true }); + rmSync(gradingSnapshot, { recursive: true, force: true }); + }; + try { + const displayedRepairBudget = args.progression + ? progressionRepairLimit + : args.repairs; + if (args.dependencyPolicy?.definition.repair.selection === 'feature' + && progressionSelection && isProgressionWorkRecipeAction(progressionSelection)) { + const [nodeId] = progressionSelection.action.repair.nodeIds; + const node = requireProgressionState(progressionExecution?.state ?? null).definition.nodes + .find(candidate => candidate.id === nodeId); + if (!nodeId || !node) { + throw new Error('feature repair has no selected feature'); + } + const used = requireProgressionState(progressionExecution?.state ?? null) + .nodes[nodeId]?.repairs.used ?? 0; + console.log(`--- feature repair ${used + 1}: ${node.title} ---`); + } else { + console.log(`--- repair ${priorRepairs + repairs + 1}/${displayedRepairBudget} ---`); + } + const fix = await runAgentForLevel('fix', level, + featureActionSequence === null ? undefined : restoreFeatureAcceptedSource); + repairCost += fix.costUsd; + repairSessions.push(runSessionRecord(fix, priorRepairs + repairs + 1)); + + const fixFailure = agentSessionFailure(fix); + if (fixFailure) { + if (featureActionSequence !== null) { + if (!await restoreAcceptedRepair(snapshot, gradingSnapshot, false)) break; + } + console.log(` coding session failed: ${fixFailure.reason}; stopping repairs`); + bundle = { outcome: fixFailure }; + repairHistory.push(repairHistoryEntry(repairs + 1, beforeBundle, bundle, + 'agent session failed')); + repairStopReason = 'agent-session-failure'; + recordRepairProgression({ failure: progressionFailure(fixFailure) }); + break; + } + repairs += 1; + + // Reject contaminated repairs before spending time on grading. + const fixLeak = auditContamination(appDir, auditNetwork(), auditsTranscripts); + if (fixLeak) { + const buildSession = build ? runSessionRecord(build) : null; + const sessions = resumedRepair || !buildSession + ? repairSessions : [buildSession, ...repairSessions]; + const sessionTotals = summarizeSessions(sessions); + cleanupRepairSnapshots(); + abortUnusableSession(`repair ${repairs}`, fixLeak, { + level, graded: false, score: null, max: null, + selection: bundle?.selection ?? null, + ...(resumedRepair + ? { resumedRepair: firstBuild } + : continuing + ? { baseline: firstBuild, resumeCostUsd: requireBuild().costUsd, + resumeSession: runSessionRecord(requireBuild()) } + : { firstBuild, buildCostUsd: requireBuild().costUsd, + buildSessions: [runSessionRecord(requireBuild())] }), + repairCostUsd: addCostUsd(repairCost), repairSessions, repairs, + ...(resumedRepair ? { priorRepairs, + cumulativeRepairs: priorRepairs + repairs } : {}), + repair: { status: 'ungraded', limit: displayedRepairBudget, + used: priorRepairs + repairs, + stopReason: fixLeak.kind === 'harness_failure' ? 'audit-failure' : 'contaminated' }, + sessionTotals, + costUsd: resumedRepair ? addCostUsd(repairCost) + : addCostUsd(requireBuild().costUsd, repairCost), + durationMs: Date.now() - t0, + }, progressionSelection, true); + } + if (hashAppSource(appDir).sha256 === acceptedSource.sha256) { + // A source hash does not cover installed dependencies or a live process. + if (!await restoreAcceptedRepair(snapshot, gradingSnapshot)) break; + const reason = 'repair made no source change'; + console.log(` ${reason}; ${args.progression + ? 'counting the failed attempt' + : 'pausing before another paid round'}`); + repairHistory.push(repairHistoryEntry(repairs, beforeBundle, beforeBundle, reason)); + if (args.progression) { + if (!restoreProgressionGrade(acceptedBundle, + `${args.backend}-l${level}-unchanged${repairs}`)) break; + if (!recordRepairProgression({ completedRepair: true })) break; + continue; + } + repairStopReason = 'no-source-change'; + break; + } + const repairedSource = `${snapshot}-accepted`; + snapshotSource(appDir, repairedSource); + try { + bundle = await gradeWithRetry({ appDir, outputDir, + label: `${args.backend}-l${level}-fix${repairs}`, + archiveLabel: `l${level}${featureActionSuffix}-repair${repairs}-before-retry`, + runGrade: label => gradeAcceptedSource(repairedSource, label) }); + } finally { + rmSync(repairedSource, { recursive: true, force: true }); + } + + const repairedOutcome = classifyBundle(bundle); + if (!levelGradeIsUsable(repairedOutcome)) { + const reason = repairedOutcome.reason + ?? 'the repaired source did not produce a reliable grade'; + // The session is paid for and charged. Keep what it produced so a + // resume grades it instead of buying another repair; the feature's + // status waits for that grade. + const candidateDirectory = `repair-candidate-l${level}${featureActionSuffix}`; + let preserveFailure: string | null = null; + try { + repairCandidate = preserveRepairCandidate(candidateDirectory); + console.log(` repair grade failed: ${reason}; kept the repaired source at ` + + `${join(outputDir, candidateDirectory)} for grading on resume`); + } catch (error) { + preserveFailure = errorMessage(error).split(/\r?\n/)[0] + ?? 'could not keep the repaired source'; + console.log(` repair grade failed: ${reason}; ${preserveFailure}; restoring the accepted source`); + if (!await restoreAcceptedRepair(snapshot, gradingSnapshot)) break; + } + repairHistory.push(repairHistoryEntry(repairs, beforeBundle, bundle, + 'repair completed; grading failed')); + recordRepairHarnessFailure('repair-grading', + preserveFailure ? `${reason}; ${preserveFailure}` : reason, bundle, true); + break; + } + + if (featureActionSequence !== null && progressionSelection + && isProgressionWorkRecipeAction(progressionSelection) + && !featureCandidateAccepted(progressionSelection, + requireProgressionState(progressionExecution?.state ?? null), bundle)) { + const rejectedBundle = bundle; + if (rejectedBundle) checkpointGrade('repair', rejectedBundle, + [...(build && !resumedRepair ? [runSessionRecord(build)] : []), ...repairSessions], false); + archiveCandidateGrade(appDir, outputDir, `l${level}${featureActionSuffix}-repair${repairs}`); + if (!await restoreAcceptedRepair(snapshot, gradingSnapshot)) break; + if (!restoreProgressionGrade(acceptedBundle, + `${args.backend}-l${level}${featureActionSuffix}-rollback${repairs}`)) break; + repairHistory.push(repairHistoryEntry(repairs, beforeBundle, rejectedBundle, + 'rolled back because the feature still failed or earlier behavior regressed')); + if (!recordRepairProgression({ completedRepair: true })) break; + if (pauseForRepeatedFindings()) break; + continue; + } + + const after = bundle?.totals?.score ?? 0; + const afterMax = bundle?.totals?.max ?? 0; + const repairedBundle = bundle; + // Lost or inconclusive evidence cannot hide a repair regression. + let decision = repairEvidenceDecision(beforeBundle, bundle); + const regressionDecision = repairRegressionDecision(acceptedBundle, bundle); + if (regressionDecision.action === 'rollback-regression') decision = regressionDecision; + if (bundle) checkpointGrade('repair', bundle, + [...(build && !resumedRepair ? [runSessionRecord(build)] : []), ...repairSessions], + !decision.action.startsWith('rollback-')); + const shared = decision.shared; + if (decision.action === 'keep-setup-repair') { + console.log(afterMax > 0 + ? ` application setup is now gradeable (${after}/${afterMax}); keeping this repair` + : ' application setup is still failing; keeping the attempted repair for the next round'); + repairHistory.push(repairHistoryEntry(repairs, beforeBundle, bundle, + afterMax > 0 + ? 'kept because the app became gradeable' + : 'kept to continue repairing application setup')); + if (!recordRepairProgression({ completedRepair: true })) break; + if (pauseForRepeatedFindings()) break; + continue; + } + if (decision.action === 'rollback-no-comparison') { + console.log(' no criteria were conclusively scored in both rounds; rolling back this fix'); + if (!await restoreAcceptedRepair(snapshot, gradingSnapshot)) break; + if (!restoreProgressionGrade(acceptedBundle, + `${args.backend}-l${level}-rollback${repairs}`)) break; + repairHistory.push(repairHistoryEntry(repairs, beforeBundle, repairedBundle, + 'rolled back because the result could not be compared')); + if (!recordRepairProgression({ completedRepair: true })) break; + if (pauseForRepeatedFindings()) break; + continue; + } + if (shared.points < Math.min(beforeMax, afterMax)) { + console.log(` comparing ${shared.points} point(s) across ${shared.count} criteria scored in both rounds` + + ` (${before}/${beforeMax} -> ${after}/${afterMax} overall)`); + } + if (decision.action === 'rollback-regression') { + if (shared.regressions.length) { + console.log(` broke ${shared.regressions.length} earlier passing check(s); rolling back this fix`); + } else if (shared.lostEvidence.length) { + console.log(` lost conclusive evidence for ${shared.lostEvidence.length} criterion/criteria; rolling back this fix`); + } else if (shared.definitionChanges.length) { + console.log(' rubric points changed between grades; rolling back this fix'); + } else { + console.log(` regressed (${shared.before} -> ${shared.after} on shared criteria); rolling back this fix`); + } + let repairRegression: ProgressionRepairRegression | null = null; + let regressionReportFailure: string | null = null; + try { + if (shared.regressions.length) { + const path = join(outputDir, 'repair-reports', + `rejected-regression-l${level}${featureActionSuffix}-round${repairs}.md`); + sh('node', [join(ROOT, 'dist', 'commands', 'report-bugs.js'), '--app', appDir, + '--out', path, '--checks-json', JSON.stringify(shared.regressions), + '--regression-context'], { stdio: 'pipe' }); + repairRegression = { + ownerNodeIds: repairOwnerNodeIds(progressionSelection), + report: readFileSync(path, 'utf8'), + }; + priorRegressionReport = path; + } + } catch (error) { + regressionReportFailure = errorMessage(error).split(/\r?\n/)[0] + ?? 'regression report generation failed'; + } + if (!await restoreAcceptedRepair(snapshot, gradingSnapshot)) break; + if (regressionReportFailure) { + repairHistory.push(repairHistoryEntry(repairs, beforeBundle, bundle, + 'repair completed; regression reporting failed')); + recordRepairHarnessFailure('repair-regression-report', regressionReportFailure, + null, true); + break; + } + if (!restoreProgressionGrade(acceptedBundle, + `${args.backend}-l${level}-rollback${repairs}`)) break; + regressed = true; + repairHistory.push(repairHistoryEntry(repairs, beforeBundle, repairedBundle, + 'rolled back because earlier behavior regressed')); + if (!recordRepairProgression({ repairRegression, completedRepair: true })) break; + if (pauseForRepeatedFindings()) break; + continue; + } + priorRegressionReport = null; + if (shared.after === shared.before) { + const remaining = displayedRepairBudget - priorRepairs - repairs; + console.log(` ${formatRepairProgress(shared, { before, beforeMax, after, afterMax })}; ` + + (remaining > 0 ? `${remaining} repair(s) remain` : 'repair budget exhausted')); + } + repairHistory.push(repairHistoryEntry(repairs, beforeBundle, bundle, + shared.after === shared.before ? 'kept with no score gain' : 'kept')); + if (!recordRepairProgression({ completedRepair: true })) break; + if (pauseForRepeatedFindings()) break; + } finally { + cleanupRepairSnapshots(); + } + } + + // Missing grade evidence is not a zero score. + const progressionState = progressionExecution + ? requireProgressionState(progressionExecution.state) : null; + const progressionAttempt = progressionState + ? progressionState.attempts.findLast(attempt => attempt.level === level) ?? null + : null; + const levelBundle = progressionAttempt?.outcome === 'inconclusive' + ? bundle : progressionBundles.get(level) ?? bundle; + const finalBundleOutcome = classifyBundle(levelBundle); + // Progression uses stricter evidence rules than a regular scored bundle. + // Store one answer when a selected check is not measured: the raw bundle + // remains available for diagnosis, but the level is not a usable grade. + const graded = levelGradeIsUsable(finalBundleOutcome, + args.progression ? progressionAttempt : null); + const finalTotals = graded ? levelBundle?.totals ?? null : null; + const nodeRepairs = progressionState + ? dependencyRepairRecords(progressionState, level, levelRepairNodeIds) + : null; + const repairLimit = progressionExecution + ? Math.max(priorRepairs + repairs, progressionRepairLimit) + : args.repairs; + const progressionStopReason = progressionNext?.type !== 'repair' + ? dependencyRepairStopReason(nodeRepairs ?? []) : null; + const repairBudgetExhausted = progressionExecution + ? finalBundleOutcome.kind === 'app_failure' && progressionStopReason !== null + && progressionStopReason !== 'repeated-findings' + : priorRepairs + repairs >= args.repairs; + repairStopReason ??= progressionStopReason; + const repairStatus: RepairStatus = repairStopReason === 'no-source-change' ? 'incomplete' + : !graded ? 'ungraded' + : finalBundleOutcome.kind === 'passed' ? (repairs > 0 ? 'corrected' : 'not-needed') + : repairBudgetExhausted ? 'budget-exhausted' : 'incomplete'; + const stopReasons: Record = { + 'not-needed': 'not-needed', + corrected: 'passed', + 'budget-exhausted': 'budget-exhausted', + incomplete: null, + ungraded: null, + }; + const stopReason = repairStopReason ?? stopReasons[repairStatus]; + const repair = { + status: repairStatus, + limit: repairLimit, + used: priorRepairs + repairs, + ...(!args.progression ? { stallLimitRounds: args.maxStalledRepairs } : {}), + stopReason, + ...(nodeRepairs ? { nodeRepairs } : {}), + ...(repairCandidate ? { candidate: repairCandidate } : {}), + }; + const latestProgressionAttempt = progressionState?.attempts.at(-1) ?? null; + const featureDepthContinues = featureActionSequence !== null + && progressionState?.phase === 'active' && progressionState.level === level; + if (continuing) { + const continuation = requireContinuation(run); + continuation.cumulativeRepairsAfter = continuation.cumulativeRepairsBefore + repairs; + } + let checkpoint = null; + if (graded && !featureDepthContinues + && (!latestProgressionAttempt || latestProgressionAttempt.level === level)) { + try { + checkpoint = preserveLevelCheckpoint({ + appDir, + outputDir: args.out, + runId, + identities: run.identities, + track: args.track, + backend: args.backend, + level, + repair, + outcome: finalBundleOutcome, + selectionSha256: levelBundle?.selection?.sha256 ?? null, + }); + console.log(` kept the L${level} source checkpoint at ${join(args.out, checkpoint.directory)}`); + } catch (error) { + console.log(` harness failure: could not keep the L${level} source checkpoint: ${errorMessage(error).split('\n')[0]}`); + } + } + if (!graded) { + console.log(` L${level}: GRADING DID NOT COMPLETE — no usable bundle. ` + + `Score is unknown, not zero; re-grade this level before using the run.`); + } + const buildSession = build ? runSessionRecord(build) : null; + const requireBuildSession = (): RunSessionRecord => { + if (!buildSession) throw new Error(`level ${level} has no coding session`); + return buildSession; + }; + const sessionTotals = summarizeSessions(resumedRepair || !buildSession ? repairSessions + : [buildSession, ...repairSessions]); + appendLevelRecord({ + level, + graded, + score: finalTotals?.score ?? null, + max: finalTotals?.max ?? null, + // Preserve earlier-level guarantees in the durable result. + regression: levelBundle?.totals?.regression ?? null, + selection: levelBundle?.selection ?? null, + ...(resumedRepair + ? { resumedRepair: firstBuild } + : continuing + ? { baseline: firstBuild, resumeCostUsd: requireBuild().costUsd, + resumeSession: requireBuildSession() } + : featureActionSequence !== null + ? { buildCostUsd: requireBuild().costUsd, buildSessions: [requireBuildSession()] } + : { firstBuild, buildCostUsd: requireBuild().costUsd, + buildSessions: [requireBuildSession()] }), + contractPass: levelBundle?.totals?.contractPass ?? null, + code: levelBundle?.code ?? null, + repairCostUsd: addCostUsd(repairCost), + repairSessions, + repairHistory, + sessionTotals, + tokens: sessionTotals.tokens, + usage: sessionTotals.usage, + turns: sessionTotals.turns, + promptBytes: sessionTotals.promptBytes, + tokensPerTurn: sessionTotals.turns + ? Math.round(sessionTotals.tokens / sessionTotals.turns) : null, + // Record actual reasoning because the provider default is not pinned. + thinking: sessionTotals.thinking, + repairs, + ...(resumedRepair ? { priorRepairs, + cumulativeRepairs: priorRepairs + repairs } : {}), + repair, + checkpoint, + // Keep the summary flag derived from the typed status so the two cannot drift. + stalled: repairStatus === 'budget-exhausted' + || ['repeated-findings', 'no-source-change'].includes(repairStopReason ?? ''), + regressed, + outcome: finalBundleOutcome, + durationSec: Math.round((Date.now() - t0) / 1000), + }); + if (!args.progression || requireProgressionState(progressionExecution?.state ?? null).attempts + .some(attempt => attempt.level === level && attempt.outcome === 'conclusive')) { + if (!featureDepthContinues && !run.validation.ladder.completedLevels.includes(level)) { + run.validation.ladder.completedLevels.push(level); + } + } + if (progressionState) synchronizeProgressionSummary(run, progressionState); + finalizeRunTotals(run, started, { costComplete: runCostComplete }); + run.outcome = aggregateRunOutcome(run.levels, progressionExecution?.state?.terminalOutcome); + persistRun(join(args.out, ARTIFACT_FILE.run), run); + if (progressionState && runCostComplete) { + commitTimeContinuationBoundary(outputDir, progressionState, level); + } + const blockedLevels = args.levelList.filter(candidate => candidate > level); + if (args.progression) { + const progressionState = requireProgressionState(progressionExecution?.state ?? null); + if (progressionState.phase === 'terminal') { + if (blockedLevels.length) run.validation.ladder.stoppedAfterLevel = level; + run.validation.ladder.blockedLevels = blockedLevels; + persistRun(join(args.out, ARTIFACT_FILE.run), run); + break; + } + if (progressionState.level <= level) { + if (progressionState.attempts.at(-1)?.outcome === 'inconclusive') { + run.validation.ladder.stoppedAfterLevel = level; + run.validation.ladder.blockedLevels = [level, ...blockedLevels]; + persistRun(join(args.out, ARTIFACT_FILE.run), run); + break; + } + if (featureActionSequence !== null && progressionState.level === level) { + levelIndex -= 1; + continue; + } + throw new Error(`dependency progression did not leave L${level} after its repair budget`); + } + continue; + } + if (blockedLevels.length && !ladderMayAdvance(finalBundleOutcome)) { + run.validation.ladder.stoppedAfterLevel = level; + run.validation.ladder.blockedLevels = blockedLevels; + persistRun(join(args.out, ARTIFACT_FILE.run), run); + console.log(` ladder paused after L${level}: L${level} must pass before ` + + `${blockedLevels.map(candidate => `L${candidate}`).join(', ')} can start`); + console.log(' inspect the failures, then explicitly grant more repairs or correct the benchmark'); + break; + } + } + + if (args.mutations) { + console.log(`\n================ ${args.backend} mutation control ================`); + const pristineOutcome = aggregateRunOutcome(run.levels, progressionExecution?.state?.terminalOutcome); + if (args.referenceMutationOnly || mutationControlEligible(pristineOutcome)) { + args.parentAttemptId = runId; + const baselineBundle = pristineMutationBaselinePath(args); + if (baselineBundle) args.mutationBaselineBundle = baselineBundle; + else delete args.mutationBaselineBundle; + run.mutationControl = runMutationControl(args, appDir, url, track, + run.setup?.isolation?.imageId ?? null); + } else { + console.log(` skipped: pristine outcome is ${pristineOutcome.kind}`); + run.mutationControl = { ok: false, skipped: true, + outcome: { kind: pristineOutcome.kind, phase: 'mutation-control-prerequisite', + reason: `pristine outcome is ${pristineOutcome.kind}` } }; + } + persistRun(join(args.out, ARTIFACT_FILE.run), run); + } + + // Record a final transcript audit in addition to the per-session hard gates. + // The same retry and diagnostic path is used at both gates. + let finalAuditFailure = null; + const finalAudit = auditContamination(appDir, auditNetwork(), auditsTranscripts); + if (!finalAudit) { + run.contaminated = false; + run.contamination = { evidence: 'no agent access to private benchmark files detected', + verdict: 'private-access audit passed' }; + } else if (finalAudit.kind === 'contaminated') { + run.contaminated = true; + run.contamination = { evidence: finalAudit.evidence, verdict: finalAudit.verdict }; + console.log('\n CONTAMINATED: restricted file or network access attempts were detected:'); + for (const evidence of finalAudit.evidence) console.log(` ${evidence}`); + console.log(' Scores from this run must not be quoted.'); + } else { + run.contaminated = false; + run.contamination = { evidence: finalAudit.evidence, verdict: finalAudit.verdict }; + const reason = finalAudit.evidence.join('; '); + finalAuditFailure = { kind: 'harness_failure', phase: 'contamination-audit', reason, + appFailures: [], inconclusive: [], harnessFailures: [reason] }; + console.log('\n HARNESS FAILURE: the contamination audit did not complete. Scores from this run must not be quoted.'); + } + + // Keep the transcript evidence outside the provider CLI's prunable store. + try { archiveTranscripts(appDir, artifactLabel); } + catch { console.log(' (transcript archiving failed — evidence is on a 30-day timer)'); } + + if (args.progression && progressionExecution?.state) { + synchronizeProgressionSummary(run, requireProgressionState(progressionExecution.state)); + } + run.outcome = finalAuditFailure ?? (args.referenceMutationOnly && run.mutationControl?.ok + ? { kind: 'passed', phase: 'mutation-control', reason: null, + appFailures: [], inconclusive: [], harnessFailures: [] } + : aggregateRunOutcome(run.levels, progressionExecution?.state?.terminalOutcome)); + if (args.mutations && !run.mutationControl?.ok && !run.mutationControl?.skipped) { + run.outcome = { kind: run.mutationControl?.outcome?.kind === 'incomplete' + ? 'incomplete' : 'harness_failure', phase: 'mutation-control', + reason: run.mutationControl?.outcome?.reason + ?? run.mutationControl?.processError + ?? 'one or more declared mutations were not cleanly caught', + appFailures: [], inconclusive: [] }; + } + + if (finalPackageEvidenceRequired(run.outcome, run.levels)) { + try { + preserveFinalPackageEvidence({ appDir, outputDir }); + console.log(` source kept at ${join(outputDir, 'source')}`); + console.log(` grading detail kept at ${join(outputDir, 'grading')}`); + } catch (error) { + const reason = errorMessage(error).split(/\r?\n/)[0] ?? 'evidence preservation failed'; + run.outcome = { kind: 'harness_failure', phase: 'evidence-preservation', reason, + appFailures: [], inconclusive: [], harnessFailures: [reason] }; + console.log(` stopped: ${reason}`); + } + } + + finalizeRunTotals(run, started, { costComplete: runCostComplete }); + if (args.repairGrant) { + const continuation = requireContinuation(run); + const totals = requireRunTotals(run); + continuation.cumulativeCostAfterUsd = addCostUsd(continuation.cumulativeCostBeforeUsd, totals.costUsd); + continuation.cumulativeDurationAfterSec = continuation.cumulativeDurationBeforeSec + totals.durationSec; + } + run.completedAt = new Date().toISOString(); + persistRun(join(args.out, ARTIFACT_FILE.run), run); + + console.log(`\n================ ${args.backend} summary ================`); + for (const l of run.levels) { + console.log(` ${formatLevelSummary(l)}`); + } + const totals = requireRunTotals(run); + console.log(` TOTAL ${totals.score}/${totals.max} ` + + `$${totals.costUsd} ${totals.repairs} repair(s) ${totals.durationSec}s`); + console.log(` ${join(outputDir, ARTIFACT_FILE.run)}`); + + teardown(); + + // Remove only the temporary directory created by this run. + if (ownWorkDir) { + try { + rmSync(dirname(appDir), { recursive: true, force: true }); + } catch (error) { + console.log(` could not remove work directory ${dirname(appDir)}: ${errorMessage(error)}`); + } + } + process.exitCode = runExitCode(run.outcome); +} + +if (process.argv[1] && pathToFileURL(resolve(process.argv[1])).href === import.meta.url) { + main().catch(error => { + console.error(redactCredentials(error instanceof Error ? error.stack ?? error.message : errorMessage(error))); + try { emergencyTeardown?.(); } + catch (cleanupError) { + console.error(`cleanup after failure also failed: ${errorMessage(cleanupError).split(/\r?\n/)[0]}`); + } + process.exitCode = 1; + }); +} diff --git a/tools/stack-bench/commands/campaign-cli.ts b/tools/stack-bench/commands/campaign-cli.ts new file mode 100644 index 00000000000..9c208a8f084 --- /dev/null +++ b/tools/stack-bench/commands/campaign-cli.ts @@ -0,0 +1,385 @@ +#!/usr/bin/env node + +import { resolve } from 'node:path'; +import { pathToFileURL } from 'node:url'; + +import { compileCampaignFile } from '../src/campaigns/campaign-compiler.js'; +import { CAMPAIGN_MODE_REGISTRY } from '../src/campaigns/campaign-mode.js'; +import { executeCampaign, inspectCampaign, reconcileCampaign } + from '../src/campaigns/campaign-runner.js'; +import { inspectCampaignSummary } from '../src/campaigns/campaign-inspection.js'; +import { exportCampaignReport, generateCampaignReport } from '../src/campaigns/campaign-report.js'; +import { grantCampaignDependencyRepairs } + from '../src/campaigns/campaign-progression-grant.js'; +import { requestCampaignTimeGrant } from '../src/campaigns/campaign-time-grant.js'; +import { readCampaignProviderContinuationStatus, requestCampaignProviderContinuation } + from '../src/campaigns/campaign-provider-continuation.js'; +import { auditProgressionReferenceCampaign, formatProgressionReferenceCampaignAudit } + from '../src/campaigns/progression-reference-campaign-audit.js'; +import type { ReferenceCampaignAudit } + from '../src/campaigns/progression-reference-campaign-audit.js'; +import { prepareCampaignExtension } from '../src/campaigns/campaign-extension.js'; +import { campaignDepthPauseStatus, continueCampaignDepth } from '../src/campaigns/campaign-depth-pause.js'; +import { statusWord } from '../src/evidence/status-words.js'; +import { readCampaignLock, requestCampaignCancellation } from '../src/campaigns/campaign-lock.js'; + +interface CampaignSummaryPlan { + id: string; + version: string; + contentSha256: string; +} + +interface CampaignSummaryState { + status: string; + summary: unknown; + attempts: Array<{ + plan: { id: string }; + status: string; + executions: Array<{ + id: string; + outcome: unknown; + reason: string | null; + }>; + }>; +} + +interface ReferenceCampaignPlan { + attempts: Array<{ + mode?: { id?: string }; + agentAdapter?: string; + }>; +} + +interface ReferenceCampaignState { + status: string; +} + +interface ResumeCampaign { + plan: { + contentSha256: string; + definition: { mode?: { id?: string } }; + }; + state: { + status: string; + attempts: Array<{ executions: readonly unknown[] }>; + }; +} + +type ReferenceCampaignAuditFunction = (directory: string) => ReferenceCampaignAudit | null; + +export type CampaignArgs = + | { command: 'pause-status'; directory: string } + | { command: 'continue-depth'; directory: string } + | { command: 'continue-provider'; directory: string; attemptId: string; requestId: string } + | { command: 'continuation-status'; directory: string; attemptId: string; json: boolean } + | { command: 'grant-time'; directory: string; attemptId: string; grantId: string; minutes: number } + | { command: 'modes' } + | { command: 'validate'; path: string } + | { command: 'show'; path: string } + | { command: 'status'; directory: string; full: boolean } + | { command: 'inspect'; directory: string } + | { command: 'report'; directory: string } + | { command: 'export'; directory: string; output: string } + | { command: 'stop'; directory: string } + | { command: 'audit'; directory: string } + | { command: 'grant-repairs'; directory: string; attemptId: string; grantId: string; + level: number; nodeIds: string[]; repairs: number } + | { command: 'extend'; path: string; parentDirectory: string; fromDepth: number; + directory: string; prepareOnly: boolean } + | { command: 'trial'; path: string; directory: string } + | { command: 'run'; path: string; directory: string } + | { command: 'resume'; path: string; directory: string } + | { command: 'reconcile'; path: string; directory: string }; + +function isOneOf(value: string | undefined, + values: readonly T[]): value is T { + return value !== undefined && values.some(candidate => candidate === value); +} + +export function campaignStateSummary(plan: CampaignSummaryPlan, state: CampaignSummaryState) { + const failures = state.attempts.flatMap(attempt => { + const execution = attempt.executions.at(-1); + if (!execution || execution.outcome === null || execution.outcome === 'passed') return []; + return [{ + attempt: attempt.plan.id, + status: statusWord(attempt.status), + execution: execution.id, + outcome: statusWord(String(execution.outcome)), + reason: execution.reason, + }]; + }); + return { + campaign: { id: plan.id, version: plan.version, sha256: plan.contentSha256 }, + status: statusWord(state.status), + summary: state.summary, + failures, + }; +} + +export function auditCompletedReferenceCampaign(directory: string, plan: ReferenceCampaignPlan, + state: ReferenceCampaignState, { + audit = auditProgressionReferenceCampaign, +}: { audit?: ReferenceCampaignAuditFunction } = {}): ReferenceCampaignAudit | null { + const hasReferenceProgression = plan.attempts.some(attempt => + attempt.mode?.id === 'dependency' && attempt.agentAdapter === 'reference-fixture'); + return state.status === 'completed' && hasReferenceProgression ? audit(directory) : null; +} + +export function validateResumeCampaignState( + requested: { contentSha256: string }, existing: T): T { + if (requested.contentSha256 !== existing.plan.contentSha256) { + throw new Error('resume requires the exact campaign plan already stored in the output directory'); + } + if (existing.plan.definition.mode?.id !== 'dependency') { + throw new Error('resume is available only for dependency campaigns'); + } + const executions = existing.state.attempts.reduce((total, attempt) => + total + attempt.executions.length, 0); + if (existing.state.status !== 'prepared' || executions < 1) { + throw new Error('resume requires a dependency campaign with scheduled work'); + } + return existing; +} + +export function validateResumeCampaign(path: string, directory: string): ResumeCampaign { + return validateResumeCampaignState(compileCampaignFile(path), inspectCampaign(directory)); +} + +export function parseCampaignArgs(argv: string[]): CampaignArgs { + const [command, path, ...rest] = argv.slice(2); + if ((command === 'pause-status' || command === 'continue-depth') && path && rest.length === 0) { + return { command, directory: resolve(path) }; + } + if ((command === 'continue-provider' || command === 'continuation-status') && path) { + const options = new Map(); + let json = false; + for (let i = 0; i < rest.length; i++) { + const flag = rest[i]!; + if (flag === '--json' && command === 'continuation-status' && !json) { json = true; continue; } + if (!['--attempt', ...(command === 'continue-provider' ? ['--request-id'] : [])].includes(flag) + || options.has(flag) || !rest[i + 1] || rest[i + 1]!.startsWith('--')) { + throw new Error('invalid provider continuation options'); + } + options.set(flag, rest[++i]!); + } + const attemptId = options.get('--attempt'); + if (!attemptId) throw new Error('provider continuation requires --attempt'); + if (command === 'continuation-status') return { command, directory: resolve(path), attemptId, json }; + const requestId = options.get('--request-id'); + if (!requestId) throw new Error('continue-provider requires --request-id'); + return { command, directory: resolve(path), attemptId, requestId }; + } + if (command === 'modes' && path === undefined) return { command }; + if (isOneOf(command, ['validate', 'show']) && path && rest.length === 0) { + return { command, path: resolve(path) }; + } + if (command === 'status' && path + && (rest.length === 0 || (rest.length === 1 && rest[0] === '--full'))) { + return { command, directory: resolve(path), full: rest.length === 1 }; + } + if (isOneOf(command, ['inspect', 'report', 'audit', 'stop']) && path && rest.length === 0) { + return { command, directory: resolve(path) }; + } + if (command === 'export' && path && rest.length === 2 && rest[0] === '--out' && rest[1]) { + return { command, directory: resolve(path), output: resolve(rest[1]) }; + } + if (command === 'grant-time' && path) { + const options = new Map(); + for (let i = 0; i < rest.length; i += 2) { + const flag = rest[i]; const value = rest[i + 1]; + if (!flag || !['--attempt', '--grant-id', '--minutes'].includes(flag) + || !value || options.has(flag)) throw new Error('invalid grant-time options'); + options.set(flag, value); + } + const minutes = Number(options.get('--minutes')); + if (!options.get('--attempt') || !options.get('--grant-id') + || !Number.isSafeInteger(minutes * 60_000) || !Number.isInteger(minutes) || minutes <= 0) { + throw new Error('grant-time requires --attempt, --grant-id, --minutes '); + } + return { command, directory: resolve(path), attemptId: options.get('--attempt')!, + grantId: options.get('--grant-id')!, minutes }; + } + if (command === 'grant-repairs' && path) { + const values: { attemptId?: string; grantId?: string; level?: number; repairs?: number; + nodeIds: string[] } = { nodeIds: [] }; + const seen = new Set(); + for (let index = 0; index < rest.length; index += 2) { + const flag = rest[index]; + const value = rest[index + 1]; + if (flag === undefined || value === undefined + || !['--attempt', '--grant-id', '--level', '--feature', '--repairs'].includes(flag) + || (flag !== '--feature' && seen.has(flag))) { + throw new Error(`invalid or duplicate grant-repairs option ${String(flag)}`); + } + seen.add(flag); + if (flag === '--attempt') values.attemptId = value; + else if (flag === '--grant-id') values.grantId = value; + else if (flag === '--level') values.level = Number(value); + else if (flag === '--repairs') values.repairs = Number(value); + else values.nodeIds.push(value); + } + if (!values.attemptId || !values.grantId || typeof values.level !== 'number' + || !Number.isSafeInteger(values.level) || typeof values.repairs !== 'number' + || !Number.isSafeInteger(values.repairs) || values.nodeIds.length === 0) { + throw new Error('grant-repairs requires --attempt, --grant-id, --level, ' + + 'one or more --feature values, and --repairs'); + } + return { command, directory: resolve(path), attemptId: values.attemptId, + grantId: values.grantId, level: values.level, nodeIds: values.nodeIds, + repairs: values.repairs }; + } + if (command === 'extend' && path && (rest.length === 6 + || (rest.length === 7 && rest[6] === '--prepare-only')) + && rest[0] === '--from' && rest[2] === '--depth' && rest[4] === '--out') { + const fromDepth = Number(rest[3]); + if (!Number.isSafeInteger(fromDepth) || fromDepth < 1) { + throw new Error('extend --depth must be a positive integer'); + } + return { command, path: resolve(path), parentDirectory: resolve(rest[1]!), + fromDepth, directory: resolve(rest[5]!), prepareOnly: rest.length === 7 }; + } + if (isOneOf(command, ['trial', 'run', 'resume', 'reconcile']) + && path && rest.length === 2 && rest[0] === '--out') { + return { command, path: resolve(path), directory: resolve(rest[1]!) }; + } + throw new Error('usage: campaign-cli.js modes | validate|show ' + + '| trial|run|resume|reconcile --out ' + + '| extend --from --depth --out [--prepare-only] ' + + '| status [--full] | inspect|report|audit|stop | export --out ' + + '| grant-repairs --attempt --grant-id --level ' + + '--feature [--feature ...] --repairs ' + + '| grant-time --attempt --grant-id --minutes ' + + '| continue-provider --attempt --request-id ' + + '| continuation-status --attempt [--json] ' + + '| pause-status|continue-depth '); +} + +async function main() { + const args = parseCampaignArgs(process.argv); + if (args.command === 'pause-status' || args.command === 'continue-depth') { + console.log(JSON.stringify(args.command === 'pause-status' + ? campaignDepthPauseStatus(args.directory) : continueCampaignDepth(args.directory), null, 2)); + return; + } + if (args.command === 'modes') { + console.log(JSON.stringify(CAMPAIGN_MODE_REGISTRY.ids.map(value => { + const [id, version] = value.split('@'); + return { id, version }; + }), null, 2)); + return; + } + if (args.command === 'status') { + const campaign = inspectCampaign(args.directory, { requireCurrentInputs: false }); + console.log(JSON.stringify(args.full + ? campaign.state + : campaignStateSummary(campaign.plan, campaign.state), null, 2)); + return; + } + if (args.command === 'inspect') { + console.log(JSON.stringify(inspectCampaignSummary(args.directory), null, 2)); + return; + } + if (args.command === 'report') { + const generated = generateCampaignReport(args.directory); + console.log(`${generated.reportPath}\n${generated.htmlPath}\n${generated.report.contentSha256}`); + return; + } + if (args.command === 'export') { + console.log(exportCampaignReport(args.directory, args.output)); + return; + } + if (args.command === 'stop') { + const lock = readCampaignLock(args.directory); + if (!lock || !requestCampaignCancellation(args.directory, + { id: lock.campaignId, contentSha256: lock.campaignSha256 }, lock.ownershipMarkerSha256)) { + throw new Error('campaign has no current controller to stop'); + } + console.log('Stop requested. The controller will stop its children and release owned resources.'); + return; + } + if (args.command === 'audit') { + const report = auditProgressionReferenceCampaign(args.directory); + if (report === null) throw new Error('campaign has no dependency reference attempts to audit'); + console.log(formatProgressionReferenceCampaignAudit(report)); + if (!report.ok) process.exitCode = 1; + return; + } + if (args.command === 'continuation-status') { + const status = readCampaignProviderContinuationStatus(args.directory, args.attemptId); + console.log(args.json ? JSON.stringify(status, null, 2) + : status.eligible ? 'Waiting: eligible for provider continuation.' : `Ineligible: ${status.reason}`); + return; + } + if (args.command === 'continue-provider') { + console.log(JSON.stringify(requestCampaignProviderContinuation(args.directory, args), null, 2)); + return; + } + if (args.command === 'grant-time') { + console.log(JSON.stringify(requestCampaignTimeGrant(args.directory, { + attemptId: args.attemptId, grantId: args.grantId, minutes: args.minutes }), null, 2)); + return; + } + if (args.command === 'grant-repairs') { + console.log(JSON.stringify(grantCampaignDependencyRepairs(args.directory, { + attemptId: args.attemptId, + grantId: args.grantId, + level: args.level, + nodeIds: args.nodeIds, + repairs: args.repairs, + }), null, 2)); + return; + } + if (args.command === 'extend') { + prepareCampaignExtension(args.path, args.parentDirectory, args.directory, args.fromDepth); + if (args.prepareOnly) { + console.log(JSON.stringify({ status: 'prepared', directory: args.directory, + parentDirectory: args.parentDirectory, fromDepth: args.fromDepth }, null, 2)); + return; + } + const plan = compileCampaignFile(args.path); + const state = await executeCampaign(args.path, args.directory, { mode: 'frozen' }); + console.log(JSON.stringify(campaignStateSummary(plan, state), null, 2)); + if (state.status !== 'completed') process.exitCode = 1; + return; + } + const plan = compileCampaignFile(args.path); + if (args.command === 'reconcile') { + const state = reconcileCampaign(args.path, args.directory); + console.log(JSON.stringify(campaignStateSummary(plan, state), null, 2)); + return; + } + if (args.command === 'trial' || args.command === 'run' || args.command === 'resume') { + if (args.command === 'resume') validateResumeCampaign(args.path, args.directory); + const cancellation = new AbortController(); + const cancel = () => cancellation.abort(); + process.on('SIGINT', cancel); + process.on('SIGTERM', cancel); + let state; + try { + const executionMode = args.command === 'trial' + || (args.command === 'resume' && plan.state === 'draft') + ? 'model-free-trial' : 'frozen'; + state = await executeCampaign(args.path, args.directory, { + mode: executionMode, + signal: cancellation.signal, + }); + } finally { + process.off('SIGINT', cancel); + process.off('SIGTERM', cancel); + } + console.log(JSON.stringify(campaignStateSummary(plan, state), null, 2)); + const audit = auditCompletedReferenceCampaign(args.directory, plan, state); + if (audit !== null) console.log(formatProgressionReferenceCampaignAudit(audit)); + if (state.status !== 'completed' || audit?.ok === false) process.exitCode = 1; + return; + } + if (args.command === 'show') console.log(JSON.stringify(plan, null, 2)); + else console.log(`${plan.id}@${plan.version} ${plan.state}: ${plan.summary.attempts} attempts, ${plan.contentSha256}`); +} + +if (process.argv[1] && pathToFileURL(resolve(process.argv[1])).href === import.meta.url) { + main().catch((error: unknown) => { + console.error(error instanceof Error ? error.message : String(error)); + process.exitCode = 2; + }); +} diff --git a/tools/stack-bench/commands/check-actions.ts b/tools/stack-bench/commands/check-actions.ts new file mode 100644 index 00000000000..adce130354a --- /dev/null +++ b/tools/stack-bench/commands/check-actions.ts @@ -0,0 +1,112 @@ +#!/usr/bin/env node +// Probes are unauthenticated or malformed and must never mutate data. + +import { parseArgs as parseNodeArgs } from 'node:util'; + +import { emptyArtifactIdentities, writeArtifact } from '../src/evidence/artifacts.js'; +import { loadTrack } from '../src/composition/tracks.js'; +import { STACK_ADAPTER_REGISTRY } from '../src/stacks/stack-adapters.js'; + +interface CheckActionsArgs { + backend?: string; + url?: string; + app?: string; + out?: string; + track?: string; + quiet?: boolean; + parentAttemptId?: string; +} + +import type { NamedAction } from '../src/composition/tracks.js'; + +interface ActionResult { + id: string; + ok: boolean; + status: number; + note: string; +} + +function parseArgs(argv: string[]): CheckActionsArgs { + const { values } = parseNodeArgs({ args: argv.slice(2), options: { + backend: { type: 'string' }, url: { type: 'string' }, app: { type: 'string' }, + out: { type: 'string' }, track: { type: 'string' }, quiet: { type: 'boolean' }, + 'parent-attempt-id': { type: 'string' }, + } }); + const a: CheckActionsArgs = { backend: values.backend, url: values.url, app: values.app, + out: values.out, track: values.track, quiet: values.quiet, + parentAttemptId: values['parent-attempt-id'] }; + if (!a.backend) { console.error('--backend is required'); process.exit(2); } + return a; +} + +const args = parseArgs(process.argv); +const backend = args.backend; +if (!backend) throw new Error('--backend is required'); + +// Use non-writing probes declared by the selected track. +const track = args.track ? loadTrack(args.track) : null; +const ACTIONS = track?.actions ?? []; +if (!ACTIONS.length) { + if (!args.quiet) console.log(` no named actions declared for track "${args.track ?? '(none)'}" — nothing to check`); + if (args.out) { + const id = `${args.parentAttemptId ?? 'actions'}-action-check`; + writeArtifact(args.out, { kind: 'action_check', id, + attempt: { id, parentId: args.parentAttemptId ?? null }, + identities: emptyArtifactIdentities({ stackAdapter: { id: backend } }), + payload: { backend, results: [], missing: [] } }); + } + process.exit(0); +} + +// SpacetimeDB control targets come from the authenticated lease. Client config +// is app-controlled input and may use environment expressions rather than +// literals; it is neither authoritative nor safe for harness operations. +const adapter = STACK_ADAPTER_REGISTRY.get(backend); +const spacetime = adapter.grading.context({ requireBuildContainer: false }); + +async function probe(action: NamedAction): Promise> { + try { + const request = adapter.namedAction.request( + { action, input: { args: action.args }, spacetime, url: args.url }); + if (!request.url) return { ok: false, status: 0, note: 'no --url given for a server-based backend' }; + const r = await fetch(request.url, { + method: request.method ?? 'POST', + headers: { 'Content-Type': 'application/json' }, + body: request.body, + }); + const rejectedByApplication = 'applicationRejectionStatuses' in request + && request.applicationRejectionStatuses.includes(r.status); + const recognizedWithoutRunning = r.status >= 400 && r.status < 500 + && ![404, 405, 429].includes(r.status); + const ok = r.ok || rejectedByApplication || recognizedWithoutRunning; + return { ok, status: r.status, + note: r.status === 404 ? request.missingNote + : ok ? '' : `action probe returned HTTP ${r.status}` }; + } catch (error: unknown) { + const message = error instanceof Error ? error.message : String(error); + return { ok: false, status: 0, note: (message.split('\n')[0] ?? '').slice(0, 90) }; + } +} + +const results: ActionResult[] = await Promise.all(ACTIONS.map(async action => ({ + id: action.id, + ...(await probe(action)), +}))); + +const missing = results.filter(r => !r.ok); +if (!args.quiet) { + for (const r of results) { + console.log(` ${r.ok ? 'ready' : 'UNUSABLE'} ${r.id.padEnd(11)} ${r.status ? `HTTP ${r.status}` : ''} ${r.note}`); + } + console.log(missing.length + ? `\n${missing.length} named action(s) unusable — contention and volume tests cannot be issued against this app.` + : '\nall named actions are ready.'); +} +if (args.out) { + const id = `${args.parentAttemptId ?? 'actions'}-action-check`; + writeArtifact(args.out, { kind: 'action_check', id, + attempt: { id, parentId: args.parentAttemptId ?? null }, + identities: emptyArtifactIdentities({ stackAdapter: { id: backend } }), + payload: { backend, results, missing: missing.map(m => m.id) } }); +} +process.exit(missing.length ? 1 : 0); diff --git a/tools/stack-bench/commands/check-calibration.ts b/tools/stack-bench/commands/check-calibration.ts new file mode 100644 index 00000000000..c7be197c7c4 --- /dev/null +++ b/tools/stack-bench/commands/check-calibration.ts @@ -0,0 +1,69 @@ +#!/usr/bin/env node + +import { existsSync, readFileSync, readdirSync } from 'node:fs'; +import { dirname, join, resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { parseArgs } from 'node:util'; + +import { compileCalibrationDefinition, compileCalibrationFile } from '../src/composition/calibration-compiler.js'; +import { buildRecipeRelease } from '../src/composition/recipe-release.js'; +import { listTracks, TRACKS_DIR } from '../src/composition/tracks.js'; + +import { STACK_BENCH_ROOT as ROOT } from '../src/package-root.js'; + +export interface CalibrationCheckResult { + track: string; + id: string; + recipe: string; + controls: number; + stacks: number; + contentSha256: string; +} + +export function checkCalibrations( + { trackName = null }: { trackName?: string | null } = {}, +): CalibrationCheckResult[] { + const availableTracks = listTracks({ includeInternal: true }); + if (trackName && !availableTracks.includes(trackName)) { + throw new Error(`unknown calibration track ${trackName}`); + } + const tracks = trackName ? [trackName] : availableTracks; + const results: CalibrationCheckResult[] = []; + for (const name of tracks) { + const trackRoot = join(TRACKS_DIR, name); + const directory = join(trackRoot, 'composition', 'calibrations'); + if (!existsSync(directory)) continue; + for (const file of readdirSync(directory).filter(candidate => candidate.endsWith('.json')).sort()) { + const path = join(directory, file); + const source = `composition/calibrations/${file}`; + const input = JSON.parse(readFileSync(path, 'utf8')); + const definition = compileCalibrationDefinition(input, { source }); + const recipePath = resolve(dirname(path), definition.recipe.path); + const release = buildRecipeRelease(recipePath, { trackRoot }); + const plan = compileCalibrationFile(path, { trackRoot, stackBenchRoot: ROOT, release }); + results.push({ track: name, id: plan.id, + recipe: plan.recipe.id, controls: plan.controls.length, stacks: plan.qualification.stacks.length, + contentSha256: plan.contentSha256 }); + } + } + return results; +} + +function main() { + const { values } = parseArgs({ args: process.argv.slice(2), options: { + track: { type: 'string' }, + }, strict: true, allowPositionals: false }); + const results = checkCalibrations({ trackName: values.track ?? null }); + for (const result of results) { + console.log(`${result.track}: ${result.id}; ` + + `${result.controls} controls, ${result.stacks} stacks, ${result.contentSha256.slice(0, 12)}`); + } +} + +if (process.argv[1] && resolve(process.argv[1]) === fileURLToPath(import.meta.url)) { + try { main(); } + catch (error: unknown) { + console.error(error instanceof Error ? error.stack ?? error.message : String(error)); + process.exitCode = 1; + } +} diff --git a/tools/stack-bench/commands/check-composition.ts b/tools/stack-bench/commands/check-composition.ts new file mode 100644 index 00000000000..49a29c5fb3f --- /dev/null +++ b/tools/stack-bench/commands/check-composition.ts @@ -0,0 +1,87 @@ +import { existsSync, readFileSync, readdirSync } from 'node:fs'; +import { join } from 'node:path'; +import { pathToFileURL } from 'node:url'; + +import { + compileFixtureDefinition, + compilePackDefinition, + compileRecipeFile, + compileRecipeSelectionFile, +} from '../src/composition/composition-compiler.js'; +import { TRACKS_DIR, listTracks } from '../src/composition/tracks.js'; + +function json(path: string): unknown { + try { return JSON.parse(readFileSync(path, 'utf8')); } + catch (error: unknown) { + const message = error instanceof Error ? error.message : String(error); + throw new Error(`cannot read composition source ${path}: ${message}`, { cause: error }); + } +} + +export interface CompositionSummary { + track: string; + packs: number; + fixtures: number; + recipes: number; + checks: number; + selections: number; +} + +export function checkCompositions( + { trackName = null }: { trackName?: string | null } = {}, +): CompositionSummary[] { + const names = trackName ? [trackName] : listTracks({ includeInternal: true }); + const summary = []; + for (const name of names) { + const trackRoot = join(TRACKS_DIR, name); + const root = join(trackRoot, 'composition'); + if (!existsSync(root)) { + if (trackName) throw new Error(`track ${name} has no composition directory`); + continue; + } + const packs = join(root, 'packs'); + const fixtures = join(root, 'fixtures'); + const recipes = join(root, 'recipes'); + const packFiles = readdirSync(packs).filter(file => file.endsWith('.json')).sort(); + const fixtureFiles = readdirSync(fixtures).filter(file => file.endsWith('.json')).sort(); + const recipeFiles = readdirSync(recipes).filter(file => file.endsWith('.json')).sort(); + if (!packFiles.length || !fixtureFiles.length || !recipeFiles.length) { + throw new Error(`track ${name} composition must contain packs, fixtures, and recipes`); + } + for (const file of packFiles) { + const path = join(packs, file); + compilePackDefinition(json(path), { source: path }); + } + for (const file of fixtureFiles) { + const path = join(fixtures, file); + compileFixtureDefinition(json(path), { source: path }); + } + const plans = recipeFiles.map(file => compileRecipeFile(join(recipes, file), { trackRoot })); + const selectionFiles = readdirSync(root).filter(file => file.endsWith('.json')).sort(); + const selections = selectionFiles.reduce((total, file) => total + + compileRecipeSelectionFile(join(root, file), { trackRoot }).entries.length, 0); + summary.push({ track: name, packs: packFiles.length, fixtures: fixtureFiles.length, + recipes: plans.length, checks: plans.reduce((total, plan) => total + plan.checks.length, 0), + selections }); + } + return summary; +} + +function main(): void { + const args = process.argv.slice(2); + let trackName: string | null = null; + for (let index = 0; index < args.length; index += 1) { + const value = args[index + 1]; + if (args[index] === '--track' && value) { + trackName = value; + index += 1; + } else throw new Error(`unknown or incomplete argument ${args[index]}`); + } + const summary = checkCompositions({ trackName }); + if (!summary.length) throw new Error('no composition sources found'); + for (const row of summary) { + console.log(`${row.track}: ${row.packs} packs, ${row.fixtures} fixtures, ${row.recipes} recipes, ${row.checks} selected checks, ${row.selections} recipe selections`); + } +} + +if (process.argv[1] && pathToFileURL(process.argv[1]).href === import.meta.url) main(); diff --git a/tools/stack-bench/commands/check-mutations.ts b/tools/stack-bench/commands/check-mutations.ts new file mode 100644 index 00000000000..042a6d9770b --- /dev/null +++ b/tools/stack-bench/commands/check-mutations.ts @@ -0,0 +1,81 @@ +#!/usr/bin/env node + +import { existsSync, readFileSync } from 'node:fs'; +import { parseArgs as parseNodeArgs } from 'node:util'; + +import { mutationFileEdits, resolveMutationFile, validateMutationDefinitions } + from '../src/evidence/mutation-analysis.js'; +import type { MutationDefinition } from '../src/evidence/mutation-analysis.js'; + +interface CliArgs { + app: string; + mutations: string; + quiet: boolean; +} + +interface MutationSpec { + anchoredTo?: unknown; + mutations?: MutationDefinition[]; +} + +function parseArgs(argv: string[]): CliArgs { + const { values: { app, mutations, quiet = false } } = parseNodeArgs({ args: argv.slice(2), + options: { app: { type: 'string' }, mutations: { type: 'string' }, quiet: { type: 'boolean' } } }); + if (!app || !mutations) { + console.error('Usage: node dist/commands/check-mutations.js --app --mutations '); + process.exit(2); + } + return { app, mutations, quiet }; +} + +const args = parseArgs(process.argv); +const parsed: unknown = JSON.parse(readFileSync(args.mutations, 'utf8')); +if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + throw new Error('mutation manifest must be an object'); +} +const spec = parsed as MutationSpec; +const say = (...message: unknown[]): void => { if (!args.quiet) console.log(...message); }; + +say(`mutations : ${args.mutations}`); +say(`app : ${args.app}`); +if (spec.anchoredTo) say(`anchored : ${String(spec.anchoredTo).split('.')[0]}`); +say(''); + +let bad = 0; +const definitions = validateMutationDefinitions(spec.mutations); +for (const issue of definitions.issues) { + console.log(` BAD MANIFEST ${issue.mutation ?? ''} -> ${issue.kind}`); + bad += 1; +} +for (const mutation of spec.mutations ?? []) { + const mutationId = String(mutation.id ?? ''); + for (const edit of mutationFileEdits(mutation)) { + let file: string; + try { file = resolveMutationFile(args.app, edit.file); } + catch { + console.log(` UNSAFE FILE ${mutationId} -> ${edit.file} escapes the app directory`); + bad += 1; + continue; + } + if (!existsSync(file)) { + console.log(` DEAD FILE ${mutationId} -> ${edit.file} does not exist in this app`); + bad += 1; + continue; + } + const source = readFileSync(file, 'utf8'); + const matches = source.split(edit.find).length - 1; + if (matches === 1) { + say(` ok ${mutationId} -> ${edit.file}`); + continue; + } + console.log(matches === 0 + ? ` DEAD ANCHOR ${mutationId} -> not found in ${edit.file}` + : ` AMBIGUOUS ${mutationId} -> matches ${matches}x in ${edit.file}; the edit would land in more than one place`); + bad += 1; + } +} + +console.log(bad + ? `\n${bad} problem(s) — these mutations cannot validate anything against this app.` + : '\nall anchors present and unique — this file can validate against this app.'); +process.exit(bad ? 1 : 0); diff --git a/tools/stack-bench/commands/check-scenarios.ts b/tools/stack-bench/commands/check-scenarios.ts new file mode 100644 index 00000000000..5ebbcca0104 --- /dev/null +++ b/tools/stack-bench/commands/check-scenarios.ts @@ -0,0 +1,315 @@ +#!/usr/bin/env node +// Check scenario action names, actors, UI hooks, and score totals without an app. + +import { existsSync, readFileSync, readdirSync } from 'node:fs'; +import { join, resolve } from 'node:path'; +import { pathToFileURL } from 'node:url'; +import { parseArgs } from 'node:util'; + +import { ACTION_REGISTRY } from '../src/actions/action-catalog.js'; +import { compileRecipeFile, type CompiledOwnedTaskFragment, type CompiledRecipeRelease } + from '../src/composition/composition-compiler.js'; +import { compileScenarioDefinition, type CompiledStep } + from '../src/composition/definition-compiler.js'; +import { DEFAULT_TRACK, listTracks, loadTrack, type Track } + from '../src/composition/tracks.js'; + +interface ScenarioScope { + features: Map>; + contractOwners: Set; + requirementOwners: Set; + contractText: string; + requirementText: string; +} + +interface RecipeSource { + baseRecipe: string | null; + isolatesSelectedSources: boolean; +} + +type HooksByLevel = Map>; + +function isRecord(value: unknown): value is Record { + return typeof value === 'object' && value !== null && !Array.isArray(value); +} + +function readJson(path: string): unknown { + return JSON.parse(readFileSync(path, 'utf8')) as unknown; +} + +function readRecipeSource(path: string): RecipeSource { + const source = readJson(path); + if (!isRecord(source)) throw new Error(`${path}: recipe must be an object`); + const task = source.task; + if (!isRecord(task)) throw new Error(`${path}: recipe task must be an object`); + const baseRecipe = task.baseRecipe; + let baseRecipePath: string | null = null; + if (baseRecipe !== undefined) { + if (!isRecord(baseRecipe) || typeof baseRecipe.path !== 'string') { + throw new Error(`${path}: task.baseRecipe.path must be a string`); + } + baseRecipePath = baseRecipe.path; + } + return { + baseRecipe: baseRecipePath, + isolatesSelectedSources: source.execution === 'all-selected-sources', + }; +} + +function contractHookIds(path: string): string[] { + const contract = readJson(path); + if (!isRecord(contract) || !Array.isArray(contract.hooks)) { + throw new Error(`${path}: hooks must be an array`); + } + return contract.hooks.map((hook, index) => { + if (!isRecord(hook) || typeof hook.id !== 'string') { + throw new Error(`${path}: hooks[${index}].id must be a string`); + } + return hook.id; + }); +} + +// Contract levels are cumulative. A level can use hooks introduced earlier. +function hooksByLevel(track: Track): HooksByLevel { + const perFile = new Map(); + for (const file of readdirSync(track.contracts).filter(name => /^\d\d-.*\.json$/.test(name))) { + perFile.set(file.slice(0, 2), contractHookIds(join(track.contracts, file))); + } + const byLevel: HooksByLevel = new Map(); + for (const level of perFile.keys()) { + const ids = [...perFile.entries()] + .filter(([candidate]) => candidate <= level) + .flatMap(([, hookIds]) => hookIds); + byLevel.set(level, new Set(ids)); + } + return byLevel; +} + +function ownedFragment( + fragment: CompiledOwnedTaskFragment, + owners: ReadonlySet, +): boolean { + return fragment.owners.some(owner => owners.has(owner)); +} + +function recipeScenarioScopes(track: Track, recipeFile: string): Map { + const recipeDir = join(track.dir, 'composition', 'recipes'); + const chain: CompiledRecipeRelease[] = []; + const seen = new Set(); + let currentFile: string | null = recipeFile; + let isolatesSelectedSources = false; + while (currentFile !== null) { + if (seen.has(currentFile)) throw new Error(`recipe base cycle at ${currentFile}`); + seen.add(currentFile); + const path = join(recipeDir, currentFile); + chain.push(compileRecipeFile(path, { trackRoot: track.dir })); + const source = readRecipeSource(path); + if (chain.length === 1) isolatesSelectedSources = source.isolatesSelectedSources; + currentFile = source.baseRecipe; + } + + const recipe = chain[0]; + if (recipe === undefined) throw new Error(`recipe chain is empty for ${recipeFile}`); + const packs = new Map(recipe.packs.map(pack => [pack.id, pack])); + const contracts = isolatesSelectedSources + ? recipe.recipe.task.contracts + : chain.flatMap(release => release.recipe.task.contracts); + const requirements = isolatesSelectedSources + ? recipe.recipe.task.requirements + : chain.flatMap(release => release.recipe.task.requirements); + const scopes = new Map(); + + const ownersFor = (check: CompiledRecipeRelease['checks'][number]): Set => { + const found = new Set([check.packId, ...(check.requiresFeatures ?? [])]); + const visit = (id: string): void => { + const pack = packs.get(id); + if (pack === undefined) return; + for (const reference of pack.requiresPacks) { + if (found.has(reference)) continue; + found.add(reference); + visit(reference); + } + }; + [...found].forEach(visit); + return found; + }; + + for (const check of recipe.checks) { + const source = check.source.replace(/^scenarios\//, ''); + const scope = scopes.get(source) ?? { + features: new Map>(), + contractOwners: new Set(), + requirementOwners: new Set(), + contractText: '', + requirementText: '', + }; + const criteria = scope.features.get(check.featureId) ?? new Set(); + criteria.add(check.criterionId); + scope.features.set(check.featureId, criteria); + for (const owner of ownersFor(check)) { + scope.contractOwners.add(owner); + scope.requirementOwners.add(owner); + } + scopes.set(source, scope); + } + + for (const scope of scopes.values()) { + const selectedContracts = isolatesSelectedSources + ? contracts.filter(fragment => ownedFragment(fragment, scope.contractOwners)) + : contracts; + const selectedRequirements = isolatesSelectedSources + ? requirements.filter(fragment => ownedFragment(fragment, scope.requirementOwners)) + : requirements; + scope.contractText = selectedContracts.map(fragment => fragment.text).join('\n'); + scope.requirementText = selectedRequirements.map(fragment => fragment.text).join('\n'); + } + return scopes; +} + +function normalizeText(text: string): string { + return text.replace(/\*\*/g, '').replace(/—/g, '-').toLowerCase().replace(/\s+/g, ' ').trim(); +} + +function promptFor(track: Track, level: string): string | null { + const dir = join(track.dir, 'prompts'); + if (!existsSync(dir)) return null; + const file = readdirSync(dir).find(name => name.startsWith(`${level}-`) && name.endsWith('.md')); + return file === undefined ? null : normalizeText(readFileSync(join(dir, file), 'utf8')); +} + +function referencedActors(step: CompiledStep): string[] { + return [step.do === 'expectCrashCheckout' ? undefined : step.from, step.fromActor] + .filter((actor): actor is string => actor !== undefined); +} + +export function referencedInterfaceValues(value: unknown, key: 'testid' | 'attribute'): string[] { + if (Array.isArray(value)) return value.flatMap(child => referencedInterfaceValues(child, key)); + if (!isRecord(value)) return []; + return Object.entries(value).flatMap(([name, child]) => name === key && typeof child === 'string' + ? [child] : referencedInterfaceValues(child, key)); +} + +function referencedTestIds(step: CompiledStep): string[] { + return referencedInterfaceValues(step, 'testid'); +} + +function main(args: readonly string[]): number { + const { values } = parseArgs({ args: [...args], options: { + track: { type: 'string' }, + recipe: { type: 'string' }, + }, strict: true, allowPositionals: false }); + const trackArg = values.track ?? null; + const recipeArg = values.recipe ?? null; + const availableTracks = listTracks(); + const trackNames = trackArg === null + ? (availableTracks.length > 0 ? availableTracks : [DEFAULT_TRACK]) + : [trackArg]; + if (recipeArg !== null && trackNames.length !== 1) { + throw new Error('--recipe requires one --track'); + } + + const knownActions = new Set(ACTION_REGISTRY.ids); + let problems = 0; + let unstatedWarnings = 0; + let staleStatementWarnings = 0; + const fail = (where: string, message: string): void => { + console.log(` ${where}: ${message}`); + problems += 1; + }; + + for (const name of trackNames) { + const track = loadTrack(name); + console.log(`# track: ${name}`); + const contracts = hooksByLevel(track); + const recipeScopes = recipeArg === null ? null : recipeScenarioScopes(track, recipeArg); + for (const file of readdirSync(track.scenarios).filter(candidate => candidate.endsWith('.json'))) { + const recipeScope = recipeScopes?.get(file); + if (recipeScopes !== null && recipeScope === undefined) continue; + const scenarioPath = join(track.scenarios, file); + let spec; + try { + spec = compileScenarioDefinition(readJson(scenarioPath), { source: scenarioPath }); + } catch (error: unknown) { + fail(file, error instanceof Error ? error.message : String(error)); + continue; + } + const level = String(spec.level).padStart(2, '0'); + const hooks = recipeScope === undefined ? (contracts.get(level) ?? null) : null; + + console.log(file); + const prompt = recipeScope === undefined + ? promptFor(track, level) + : normalizeText(recipeScope.requirementText); + for (const feature of spec.features) { + const selectedCriteria = recipeScope?.features.get(feature.id); + if (recipeScope !== undefined && selectedCriteria === undefined) continue; + const criteria = selectedCriteria === undefined + ? feature.criteria + : feature.criteria.filter(criterion => selectedCriteria.has(criterion.id)); + for (const criterion of criteria) { + if (criterion.statedBy !== undefined) { + if (recipeScope === undefined && prompt !== null + && !prompt.includes(normalizeText(criterion.statedBy))) { + staleStatementWarnings += 1; + console.log(` warn F${feature.id} ${criterion.id}: statedBy text is not in the level ${level} prompt`); + } + } else if (recipeScope === undefined && criterion.points > 0) { + unstatedWarnings += 1; + console.log(` warn F${feature.id} ${criterion.id}: carries ${criterion.points} point(s) with no statedBy - the requirement may be unstated`); + } + } + + const actors = new Set(feature.actors ?? []); + const steps = [...feature.setup, ...criteria.flatMap(criterion => criterion.steps)]; + const declared = (actor: string): boolean => actors.has(actor) + || [...actors].some(candidate => actor.startsWith(`${candidate}-`)); + for (const step of steps) { + const at = `F${feature.id} ${step.do}`; + if (!knownActions.has(step.do)) fail(at, `unknown step type "${step.do}"`); + if (step.actor !== undefined && actors.size > 0 && !declared(step.actor)) { + fail(at, `actor "${step.actor}" is not in the feature's actor list`); + } + for (const actor of referencedActors(step)) { + if (actors.size > 0 && !declared(actor)) { + fail(at, `actor "${actor}" is not in the feature's actor list`); + } + } + if (hooks !== null) { + for (const id of referencedTestIds(step)) { + if (!hooks.has(id)) fail(at, `testid "${id}" is not in the contract`); + } + } + if (recipeScope !== undefined) { + for (const id of referencedTestIds(step)) { + if (!recipeScope.contractText.includes(`\`${id}\``)) { + fail(at, `testid "${id}" is not in the selected recipe contracts`); + } + } + for (const attribute of referencedInterfaceValues(step, 'attribute')) { + if (attribute.startsWith('data-') && !recipeScope.contractText.includes(`\`${attribute}\``)) { + fail(at, `attribute "${attribute}" is not in the selected recipe contracts`); + } + } + } + } + + const points = criteria.reduce((total, criterion) => total + criterion.points, 0); + if (recipeScope === undefined && feature.max !== undefined && points !== feature.max) { + fail(`F${feature.id}`, `criteria total ${points} but max says ${feature.max}`); + } + } + } + } + + const warnings = unstatedWarnings + staleStatementWarnings; + console.log(problems > 0 + ? `\n${problems} error(s); ${warnings} warning(s)` + : warnings > 0 + ? `\n0 errors; ${warnings} warning(s) (${unstatedWarnings} point-carrying criteria lack statedBy; ${staleStatementWarnings} statedBy references are outside level prompts)` + : '\n0 errors; 0 warnings'); + return problems > 0 ? 1 : 0; +} + +if (process.argv[1] && pathToFileURL(resolve(process.argv[1])).href === import.meta.url) { + process.exitCode = main(process.argv.slice(2)); +} diff --git a/tools/stack-bench/commands/composition-cli.ts b/tools/stack-bench/commands/composition-cli.ts new file mode 100644 index 00000000000..13411828c2c --- /dev/null +++ b/tools/stack-bench/commands/composition-cli.ts @@ -0,0 +1,315 @@ +#!/usr/bin/env node + +import { existsSync, readdirSync, realpathSync } from 'node:fs'; +import { join, relative, resolve, sep } from 'node:path'; +import { pathToFileURL } from 'node:url'; +import { parseArgs } from 'node:util'; + +import { compilePackDefinition, compileRecipeFile, resolveTaskFragment } from '../src/composition/composition-compiler.js'; +import { compileScenarioDefinition } from '../src/composition/definition-compiler.js'; +import { canonicalDefinitionJson, readDefinitionJson } + from '../src/composition/definition-plan.js'; +import { buildRecipeRelease } from '../src/composition/recipe-release.js'; +import { composeSelectedRecipeTask, selectRecipeRelease } from '../src/composition/recipe-selection.js'; +import { TRACKS_DIR } from '../src/composition/tracks.js'; +import type { CompiledPackDefinition, CompiledRecipePlan } from '../src/composition/composition-compiler.js'; +import type { RecipeRelease } from '../src/composition/recipe-release.js'; +import type { RecipeSelectionOptions, SelectedRecipeRelease } from '../src/composition/recipe-selection.js'; + +export { selectRecipeRelease } from '../src/composition/recipe-selection.js'; + +interface TrackRootOptions { + trackRoot: string; +} + +interface PackIndexEntry { + pack: CompiledPackDefinition; + path: string; +} + +interface CalibrationValue { + id: string; + recipe?: { id?: string; contentSha256?: string }; +} + +type RecipeOptions = TrackRootOptions & RecipeSelectionOptions; +type RecipeTaskKind = 'requirements' | 'contracts'; + +function contained(root: string, path: string, label: string): string { + const absoluteRoot = realpathSync(resolve(root)); + const candidate = resolve(path); + const lexical = relative(absoluteRoot, candidate); + if (lexical === '..' || lexical.startsWith(`..${sep}`)) throw new Error(`${label} escapes ${absoluteRoot}`); + if (!existsSync(candidate)) throw new Error(`${label} does not exist: ${candidate}`); + const absolute = realpathSync(candidate); + const physical = relative(absoluteRoot, absolute); + if (physical === '..' || physical.startsWith(`..${sep}`)) throw new Error(`${label} escapes ${absoluteRoot}`); + return absolute; +} + +function packIndex(trackRoot: string): Map { + const directory = join(trackRoot, 'composition', 'packs'); + const byRef = new Map(); + for (const name of readdirSync(directory).filter(file => file.endsWith('.json')).sort()) { + const path = join(directory, name); + const pack = compilePackDefinition(readDefinitionJson(path, 'pack'), { + source: relative(trackRoot, path).replaceAll('\\', '/'), + }); + if (byRef.has(pack.id)) throw new Error(`duplicate pack id ${pack.id}`); + byRef.set(pack.id, { pack, path: realpathSync(path) }); + } + for (const [ref, { pack }] of byRef) { + for (const dependency of [...pack.requiresPacks, ...pack.conflictsWith]) { + if (!byRef.has(dependency)) throw new Error(`${ref} references missing pack ${dependency}`); + } + } + return byRef; +} + +export function validatePackFile(path: string, options: Partial = {}) { + const { trackRoot } = options; + if (trackRoot === undefined) throw new Error('pack validation requires trackRoot'); + const root = realpathSync(resolve(trackRoot)); + const absolute = contained(join(root, 'composition'), path, 'pack path'); + const pack = compilePackDefinition(readDefinitionJson(absolute, 'pack'), { + source: relative(root, absolute).replaceAll('\\', '/'), + }); + const packs = packIndex(root); + const indexed = packs.get(pack.id); + if (!indexed || indexed.path !== absolute) throw new Error(`${pack.id} is not the indexed source ${absolute}`); + for (const ref of [...pack.requiresPacks, ...pack.conflictsWith]) { + if (!packs.has(ref)) throw new Error(`${pack.id} references missing pack ${ref}`); + } + const sourceCache = new Map(); + for (const kind of ['requirements', 'contracts'] satisfies RecipeTaskKind[]) { + for (const fragment of pack.task[kind]) { + resolveTaskFragment(fragment, { trackRoot: root, + source: `${relative(root, absolute).replaceAll('\\', '/')}.task.${kind}.${fragment.id}`, + sourceCache }); + } + } + const state = new Map(); + const visit = (ref: string, chain: string[] = []): void => { + if (state.get(ref) === 'done') return; + if (state.get(ref) === 'visiting') throw new Error(`pack dependency cycle: ${[...chain, ref].join(' -> ')}`); + state.set(ref, 'visiting'); + const entry = packs.get(ref); + if (!entry) throw new Error(`missing pack release ${ref}`); + for (const dependency of entry.pack.requiresPacks) { + if (!packs.has(dependency)) throw new Error(`${ref} references missing pack ${dependency}`); + visit(dependency, [...chain, ref]); + } + state.set(ref, 'done'); + }; + visit(pack.id); + let criteria = 0; + for (const check of pack.checks) { + const scenarioPath = contained(root, join(root, check.source), `${pack.id}.${check.id}.source`); + const scenario = compileScenarioDefinition(readDefinitionJson(scenarioPath, 'scenario'), { + source: relative(root, scenarioPath).replaceAll('\\', '/'), + }); + const feature = scenario.features.find(candidate => candidate.id === check.feature); + if (!feature) throw new Error(`${pack.id}.${check.id} references missing feature ${check.feature}`); + criteria += feature.criteria.length; + } + return { id: pack.id, path: absolute, + checkGroups: pack.checks.length, criteria, requiresPacks: pack.requiresPacks }; +} + +export function validateRecipeFile(path: string, options: Partial = {}): { + plan: CompiledRecipePlan; + release: RecipeRelease; +} { + const { trackRoot } = options; + if (trackRoot === undefined) throw new Error('recipe validation requires trackRoot'); + const absolute = contained(join(trackRoot, 'composition'), path, 'recipe path'); + const plan = compileRecipeFile(absolute, { trackRoot }); + const release = buildRecipeRelease(absolute, { trackRoot }); + return { plan, release }; +} + +export function showRecipeFile(path: string, options: RecipeOptions): SelectedRecipeRelease & { + builderTask: ReturnType & { note: string }; +} { + const compiled = validateRecipeFile(path, options); + const selected = selectRecipeRelease(compiled.release, options); + const builderTask = composeSelectedRecipeTask(compiled.plan, selected.selection); + return { + ...selected, + builderTask: { + ...builderTask, + note: 'Pack selection defines the requested task; a check-only filter narrows measurement inside it.', + }, + }; +} + +const same = (left: unknown, right: unknown): boolean => + canonicalDefinitionJson(left) === canonicalDefinitionJson(right); + +function meaningView(release: RecipeRelease) { + return { + track: release.track, + task: release.task, + checks: release.checkCatalog.map(({ stableKey, packId, checkGroupId, role, source, + featureId, criterionId, description }) => ({ stableKey, packId, checkGroupId, role, + source, featureId, criterionId, description })), + }; +} + +function scoringView(release: RecipeRelease) { + return { scoring: release.scoring, + checks: release.checkCatalog.map(({ stableKey, points }) => ({ stableKey, points })) }; +} + +function metadataView(release: RecipeRelease) { + return { id: release.id, title: release.title, + sequence: release.sequence, sourceManifestSha256: release.sourceManifestSha256 }; +} + +function matchingCalibrations(trackRoot: string, release: RecipeRelease): Array<{ + path: string; + value: CalibrationValue; +}> { + const directory = join(trackRoot, 'composition', 'calibrations'); + if (!existsSync(directory)) return []; + return readdirSync(directory).filter(name => name.endsWith('.json')).sort() + .map(name => ({ path: join(directory, name), + value: readDefinitionJson(join(directory, name), 'calibration') })) + .filter(({ value }) => value.recipe?.id === release.id + && value.recipe?.contentSha256 === release.contentSha256); +} + +export function diffRecipeFiles(fromPath: string, toPath: string, options: Partial = {}) { + const { trackRoot } = options; + if (trackRoot === undefined) throw new Error('recipe diff requires trackRoot'); + const from = validateRecipeFile(fromPath, { trackRoot }).release; + const to = validateRecipeFile(toPath, { trackRoot }).release; + const categories = { + meaning: !same(meaningView(from), meaningView(to)), + scoring: !same(scoringView(from), scoringView(to)), + fixtures: !same(from.components.fixture, to.components.fixture), + execution: from.executionSha256 !== to.executionSha256, + metadata: !same(metadataView(from), metadataView(to)), + }; + const recipeBindingChanged = from.id !== to.id + || from.meaningSha256 !== to.meaningSha256 || from.executionSha256 !== to.executionSha256 + || from.contentSha256 !== to.contentSha256; + const calibrations = matchingCalibrations(trackRoot, from).map(({ path, value }) => { + const invalidated = []; + if (recipeBindingChanged) invalidated.push('recipe binding'); + if (categories.fixtures) invalidated.push('fixture binding'); + if (categories.scoring) invalidated.push('zero-point control policy'); + if (categories.meaning || categories.scoring || categories.execution || categories.fixtures) { + invalidated.push('reference repetitions', 'mutation repetitions'); + } + if (categories.meaning || categories.scoring || categories.fixtures) invalidated.push('null repetitions'); + if (recipeBindingChanged) invalidated.push('selection binding'); + return { id: value.id, + path: relative(trackRoot, path).replaceAll('\\', '/'), invalidated: [...new Set(invalidated)] }; + }); + const fragmentDiff = (kind: RecipeTaskKind) => { + const before = new Map(from.task[kind].map(fragment => [fragment.id, fragment])); + const after = new Map(to.task[kind].map(fragment => [fragment.id, fragment])); + return { + added: [...after.keys()].filter(key => !before.has(key)).sort(), + removed: [...before.keys()].filter(key => !after.has(key)).sort(), + changed: [...after.keys()].filter(key => before.has(key) + && !same(before.get(key), after.get(key))).sort(), + }; + }; + return { + from: { id: from.id, meaningSha256: from.meaningSha256, + executionSha256: from.executionSha256, contentSha256: from.contentSha256 }, + to: { id: to.id, meaningSha256: to.meaningSha256, + executionSha256: to.executionSha256, contentSha256: to.contentSha256 }, + categories, + taskFragments: { + requirements: fragmentDiff('requirements'), + contracts: fragmentDiff('contracts'), + composedTaskChanged: from.task.composedSha256 !== to.task.composedSha256, + }, + calibrations, + }; +} + +type CliSubject = 'pack' | 'recipe'; +type CliCommand = 'validate' | 'show' | 'diff'; + +interface ParsedArgs extends RecipeSelectionOptions { + json: boolean; + positional: string[]; + packIds: string[]; + checkKeys: string[]; + track?: string; + trackRoot?: string; +} + +interface CliArgs extends ParsedArgs { + subject: CliSubject; + command: CliCommand; + paths: string[]; + trackRoot: string; +} + +function parse(argv: string[]): CliArgs { + const { positionals, values } = parseArgs({ args: argv.slice(2), allowPositionals: true, + options: { track: { type: 'string' }, 'track-root': { type: 'string' }, + pack: { type: 'string', multiple: true }, check: { type: 'string', multiple: true }, + json: { type: 'boolean' } } }); + const args: ParsedArgs = { json: values.json ?? false, positional: positionals, + packIds: (values.pack ?? []).flatMap(value => value.split(',').filter(Boolean)), + checkKeys: (values.check ?? []).flatMap(value => value.split(',').filter(Boolean)), + track: values.track, + trackRoot: values['track-root'] === undefined ? undefined : resolve(values['track-root']) }; + const [subject, command, ...paths] = args.positional; + if (subject !== 'pack' && subject !== 'recipe') { + throw new Error('usage: npm run pack -- validate --track | npm run recipe -- validate|show --track | npm run recipe -- diff --track '); + } + if (command !== 'validate' && command !== 'show' && command !== 'diff') { + throw new Error('usage: npm run pack -- validate --track | npm run recipe -- validate|show --track | npm run recipe -- diff --track '); + } + if (subject === 'pack' && command !== 'validate') throw new Error(`pack ${command} is not supported`); + if ((command === 'diff' ? paths.length !== 2 : paths.length !== 1)) throw new Error(`${subject} ${command} received the wrong number of paths`); + if (!args.trackRoot && !args.track) throw new Error('--track or --track-root is required'); + if ((args.packIds.length || args.checkKeys.length) && !(subject === 'recipe' && command === 'show')) { + throw new Error('--pack and --check are allowed only with recipe show'); + } + const trackRoot = args.trackRoot ?? join(TRACKS_DIR, args.track ?? ''); + return { ...args, subject, command, paths, trackRoot }; +} + +function main() { + const args = parse(process.argv); + const firstPath = args.paths[0]; + if (firstPath === undefined) throw new Error('command requires a source path'); + let result: object; + if (args.subject === 'pack') result = validatePackFile(firstPath, args); + else if (args.command === 'diff') { + const secondPath = args.paths[1]; + if (secondPath === undefined) throw new Error('recipe diff requires two source paths'); + result = diffRecipeFiles(firstPath, secondPath, args); + } else if (args.command === 'show') result = showRecipeFile(firstPath, args); + else { + const compiled = validateRecipeFile(firstPath, args); + result = { + id: compiled.release.id, + packs: compiled.release.components.packs.length, checks: compiled.release.checkCatalog.length, + points: compiled.release.checkCatalog.reduce((total, check) => total + check.points, 0), + meaningSha256: compiled.release.meaningSha256, + executionSha256: compiled.release.executionSha256, + contentSha256: compiled.release.contentSha256, + }; + } + if (args.json || args.command === 'show' || args.command === 'diff') console.log(JSON.stringify(result, null, 2)); + else if ('id' in result) { + console.log(`${String(result.id)}: valid`); + } else throw new Error('validation result has no release identity'); +} + +if (process.argv[1] && pathToFileURL(process.argv[1]).href === import.meta.url) { + try { main(); } + catch (error) { + console.error(error instanceof Error ? error.message : String(error)); + process.exitCode = 2; + } +} diff --git a/tools/stack-bench/commands/container-smoke.ts b/tools/stack-bench/commands/container-smoke.ts new file mode 100644 index 00000000000..153d24c91da --- /dev/null +++ b/tools/stack-bench/commands/container-smoke.ts @@ -0,0 +1,205 @@ +#!/usr/bin/env node +// Use only ephemeral resources owned by this smoke run. + +import { spawn, execFileSync } from 'node:child_process'; +import type { ChildProcess } from 'node:child_process'; +import { cpSync, existsSync, mkdirSync, mkdtempSync, rmSync } from 'node:fs'; +import { createServer } from 'node:net'; +import type { AddressInfo } from 'node:net'; +import { basename, join, resolve } from 'node:path'; +import { tmpdir } from 'node:os'; +import { setTimeout as delay } from 'node:timers/promises'; + +import { killTree, pidsOnPort, processIdentity } from '../src/runtime/platform.js'; +import { createBackendLease, readBackendLease, writeBackendLease } from '../src/runtime/backend-lease.js'; +import { fetchStatus } from '../src/runtime/readiness.js'; +import { DEFAULT_BUILD_IMAGE } from '../src/composition/product-config.js'; +import { containerReachableSpacetimeUri } from '../src/runtime/spacetime-target.js'; +import { CODING_CONTAINER_APP_ROOT, CODING_CONTAINER_SPACETIME_CLI, + codingContainerAgentExecOptions } from '../src/runtime/coding-container-policy.js'; +import { ARTIFACT_FILE } from '../src/evidence/artifacts.js'; + +import { STACK_BENCH_ROOT as ROOT, compiledEntrypoint } from '../src/package-root.js'; +const REPO = resolve(ROOT, '..', '..'); +const IMAGE = process.env.STACK_BENCH_IMAGE ?? DEFAULT_BUILD_IMAGE; +const CLI = process.env.SPACETIME_BIN ?? join(REPO, 'target', 'release', + process.platform === 'win32' ? 'spacetimedb-cli.exe' : 'spacetimedb-cli'); +const RUN_BUILD = compiledEntrypoint('container', 'run-build.js'); +const FIXTURE = join(ROOT, 'tests', 'fixtures', 'spacetime-module'); + +interface PreparedContainerIdentity { + containerName: string; + identity: string; + networkMode: string | null; +} + +function isRecord(value: unknown): value is Record { + return value !== null && typeof value === 'object' && !Array.isArray(value); +} + +function parsePreparedContainerIdentity(text: string): PreparedContainerIdentity { + const value: unknown = JSON.parse(text.trim().split(/\r?\n/).pop() ?? ''); + if (!isRecord(value)) throw new Error('prepared container identity is invalid'); + const record = value; + if (typeof record.containerName !== 'string' || typeof record.identity !== 'string' + || (record.networkMode !== null && typeof record.networkMode !== 'string')) { + throw new Error('prepared container identity is invalid'); + } + return { containerName: record.containerName, identity: record.identity, networkMode: record.networkMode }; +} + +async function freePort() { + const server = createServer(); + await new Promise((ok, fail) => server.listen({ port: 0, host: '127.0.0.1' }, ok).once('error', fail)); + const address = server.address(); + if (!address || typeof address === 'string') throw new Error('could not allocate a TCP port'); + const port: AddressInfo['port'] = address.port; + await new Promise(ok => server.close(ok)); + return port; +} + +async function waitFor(check: () => boolean | Promise, timeoutMs: number, description: string): Promise { + const deadline = Date.now() + timeoutMs; + while (Date.now() < deadline) { + if (await check()) return; + await delay(250); + } + throw new Error(`timed out waiting for ${description}`); +} + +async function main() { + if (!existsSync(CLI)) throw new Error(`local SpacetimeDB CLI is missing: ${CLI}`); + execFileSync('docker', ['image', 'inspect', IMAGE], { stdio: 'pipe' }); + + const root = mkdtempSync(join(tmpdir(), 'stack-bench-container-smoke-')); + const app = join(root, 'app'); + const dataDir = join(root, 'spacetime-data'); + const port = await freePort(); + const uri = `http://127.0.0.1:${port}`; + const module = `stackbench-container-smoke-${process.pid}`; + const containerName = `stack-bench-${basename(root)}`; + const leasePath = join(root, ARTIFACT_FILE.backendLease); + let host: ChildProcess | null = null; + let dev: ChildProcess | null = null; + let output = ''; + + try { + mkdirSync(app, { recursive: true }); + host = spawn(CLI, ['start', '--listen-addr', `127.0.0.1:${port}`, '--data-dir', dataDir], + { stdio: 'ignore', windowsHide: true }); + await waitFor(async () => { + const status = await fetchStatus(`${uri}/v1/ping`, { timeoutMs: 5000 }); + return status !== null && status >= 200 && status < 300; + }, 120_000, `dedicated SpacetimeDB host on :${port}`); + + const lease = createBackendLease({ runId: basename(root), backend: 'spacetime', + track: 'container-smoke', runIndex: 0, serverUri: uri, module, dataDir }); + lease.state = 'active'; + lease.resources.launchedProcess = host.pid ? processIdentity(host.pid) : null; + lease.resources.listenerProcesses = pidsOnPort(port).map(pid => processIdentity(pid)) + .filter((identity): identity is NonNullable => identity !== null); + writeBackendLease(leasePath, lease); + + const prepared = execFileSync(process.execPath, + [RUN_BUILD, '--app', app, '--backend', 'spacetime', '--image', IMAGE, '--prepare-only'], + { encoding: 'utf8', stdio: 'pipe', maxBuffer: 16 * 1024 * 1024, + env: { ...process.env, STACK_BENCH_LEASE: leasePath, + STACK_BENCH_LEASE_TOKEN: lease.ownershipToken, STACK_BENCH_STDB_URI: uri } }); + const identity = parsePreparedContainerIdentity(prepared); + if (identity.containerName !== containerName) { + throw new Error(`prepared unexpected container ${identity.containerName}`); + } + const leasedContainer = readBackendLease(leasePath, + { token: lease.ownershipToken, backend: 'spacetime', active: true }).resources.buildContainer; + if (!leasedContainer || identity.identity.split(' ')[0] !== leasedContainer.id) { + throw new Error('prepared container identity was not recorded in the backend lease'); + } + if (!leasedContainer.image || !/^sha256:[0-9a-f]{64}$/.test(leasedContainer.image)) { + throw new Error(`prepared container did not record an immutable image id: ${leasedContainer.image}`); + } + + cpSync(FIXTURE, join(app, 'spacetimedb'), { recursive: true }); + const agentExec = ['exec', ...codingContainerAgentExecOptions()]; + const browserDom = execFileSync('docker', [...agentExec, containerName, 'chromium', + '--headless', '--no-sandbox', '--disable-dev-shm-usage', '--dump-dom', + 'data:text/html,'], + { encoding: 'utf8', stdio: 'pipe', timeout: 30_000 }); + if (!browserDom.includes('42')) throw new Error('agent browser did not execute JavaScript'); + const cliAccess = execFileSync('docker', [...agentExec, containerName, 'sh', '-c', + `stat -c '%a %U %G' ${CODING_CONTAINER_SPACETIME_CLI}; test -x ${CODING_CONTAINER_SPACETIME_CLI}`], + { encoding: 'utf8', stdio: 'pipe' }); + if (!/^755 root root/m.test(cliAccess)) throw new Error(`unexpected CLI access: ${cliAccess.trim()}`); + execFileSync('docker', [...agentExec, containerName, 'sh', '-c', + `umask 000; cd ${CODING_CONTAINER_APP_ROOT}/spacetimedb && npm install --no-audit --no-fund`], + { stdio: 'pipe' }); + + const startedDev = spawn('docker', [...agentExec, '-i', containerName, 'sh', '-c', + `umask 000; cd ${CODING_CONTAINER_APP_ROOT}/spacetimedb && ${CODING_CONTAINER_SPACETIME_CLI} dev ${module} ` + + `--project-path ${CODING_CONTAINER_APP_ROOT}/spacetimedb --module-path . ` + + '--server-only --skip-generate ' + + `-s ${containerReachableSpacetimeUri({ resources: { serverUri: uri, + buildContainer: lease.resources.buildContainer } }, identity.networkMode)} -y`], + { stdio: ['ignore', 'pipe', 'pipe'], windowsHide: true }); + dev = startedDev; + const collect = (chunk: Buffer): void => { output = (output + chunk.toString()).slice(-128 * 1024); }; + startedDev.stdout?.on('data', collect); + startedDev.stderr?.on('data', collect); + + await waitFor(() => { + if (/Published successfully!/.test(output)) return true; + if (startedDev.exitCode !== null) throw new Error(`spacetime dev exited ${startedDev.exitCode}:\n${output}`); + return false; + }, 240_000, 'containerized module publish'); + + const sql = execFileSync(CLI, ['sql', module, 'SELECT * FROM smoke_item', '-s', uri], + { encoding: 'utf8', stdio: 'pipe' }); + if (!/\bid\s*\|\s*value\b/.test(sql)) throw new Error(`SQL verification failed:\n${sql}`); + if (startedDev.exitCode !== null) throw new Error('spacetime dev did not remain alive as a watcher'); + + // Publishing and log streaming must retain one authenticated identity. A + // prior dev bug published with a token stored only in a Config clone, then + // directly logged in again for logs and received an authorization error. + await delay(2_000); + const logStreamingAuthorized = !/Log streaming error:.*not authorized/s.test(output); + console.log(JSON.stringify({ ok: true, image: IMAGE, container: identity.identity, + host: { uri, listenerPids: pidsOnPort(port) }, published: true, sqlVerified: true, + watcherAlive: true, leasedContainer: true, immutableImagePinned: true, + logStreamingAuthorized }, null, 2)); + if (!logStreamingAuthorized) { + throw new Error('`spacetime dev` published successfully but its log stream was not authorized'); + } + // The grader resets by republishing the same named database from this exact + // leased container. Prove that `-y` retained a reusable local identity, + // rather than merely proving that the first anonymous-looking publish ran. + execFileSync('docker', [...agentExec, containerName, 'sh', '-c', + 'for process in /proc/[0-9]*; do ' + + 'test "$(readlink "$process/exe" 2>/dev/null)" = /deps/.spacetimedb-cli ' + + '&& kill -TERM "${process##*/}" || true; done'], { stdio: 'pipe' }); + await waitFor(() => startedDev.exitCode !== null, 15_000, 'spacetime dev to stop before reset publish'); + const targetUri = containerReachableSpacetimeUri({ resources: { serverUri: uri, + buildContainer: lease.resources.buildContainer } }, identity.networkMode); + execFileSync('docker', [...agentExec, containerName, 'sh', '-c', + `umask 000; cd ${CODING_CONTAINER_APP_ROOT}/spacetimedb && ${CODING_CONTAINER_SPACETIME_CLI} publish ${module} ` + + `--module-path . -s ${targetUri} --delete-data -y`], + { stdio: 'pipe', timeout: 240_000 }); + const afterReset = execFileSync(CLI, ['sql', module, 'SELECT * FROM smoke_item', '-s', uri], + { encoding: 'utf8', stdio: 'pipe' }); + if (!/\bid\s*\|\s*value\b/.test(afterReset)) { + throw new Error(`SQL verification after reset publish failed:\n${afterReset}`); + } + console.log(JSON.stringify({ resetRepublished: true, resetSqlVerified: true })); + } finally { + if (dev && dev.exitCode === null) dev.kill('SIGTERM'); + try { execFileSync('docker', ['rm', '-f', containerName], { stdio: 'ignore' }); } catch { /* absent */ } + // The port was proven unused before this script started the host. Kill only + // listeners on that exact ephemeral port, then the wrapper if it remains. + for (const pid of pidsOnPort(port)) killTree(pid); + if (host && host.exitCode === null) killTree(host.pid); + rmSync(root, { recursive: true, force: true }); + } +} + +main().catch(error => { + console.error(error.stack ?? error.message); + process.exitCode = 1; +}); diff --git a/tools/stack-bench/commands/definition-snapshots.ts b/tools/stack-bench/commands/definition-snapshots.ts new file mode 100644 index 00000000000..9f227e19d30 --- /dev/null +++ b/tools/stack-bench/commands/definition-snapshots.ts @@ -0,0 +1,80 @@ +import { mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs'; +import { dirname, join } from 'node:path'; +import { pathToFileURL } from 'node:url'; + +import { compileScenarioDefinition } from '../src/composition/definition-compiler.js'; +import { canonicalDefinitionJson, compileTrackPlan } from '../src/composition/definition-plan.js'; +import { listTracks } from '../src/composition/tracks.js'; +import { STACK_BENCH_ROOT } from '../src/package-root.js'; + +const SNAPSHOT_DIR = join(STACK_BENCH_ROOT, 'tests', 'snapshots', 'definitions'); +const ALL_ACTIONS = join(STACK_BENCH_ROOT, 'tests', 'fixtures', 'definitions', 'all-actions.json'); + +function atomicWrite(path: string, contents: string): void { + mkdirSync(dirname(path), { recursive: true }); + const temporary = `${path}.tmp-${process.pid}`; + writeFileSync(temporary, contents); + renameSync(temporary, path); +} + +interface DefinitionSnapshot { + name: string; + value: unknown; +} + +export function currentDefinitionSnapshots(): DefinitionSnapshot[] { + const entries: DefinitionSnapshot[] = listTracks({ includeInternal: true }).map(name => ({ + name: `${name}.snapshot.json`, + value: compileTrackPlan(name), + })); + entries.push({ + name: 'all-actions.snapshot.json', + value: compileScenarioDefinition(JSON.parse(readFileSync(ALL_ACTIONS, 'utf8')), { + source: ALL_ACTIONS, + }), + }); + return entries.sort((a, b) => a.name.localeCompare(b.name)); +} + +export interface DefinitionSnapshotResult { + checked: number; + changed: string[]; +} + +export function checkDefinitionSnapshots( + { update = false }: { update?: boolean } = {}, +): DefinitionSnapshotResult { + const entries = currentDefinitionSnapshots(); + const changed: string[] = []; + for (const entry of entries) { + const path = join(SNAPSHOT_DIR, entry.name); + const actual = canonicalDefinitionJson(entry.value); + let expected: string | null = null; + try { + expected = readFileSync(path, 'utf8').replaceAll('\r\n', '\n'); + } catch (error: unknown) { + if (!(error instanceof Error && 'code' in error && error.code === 'ENOENT')) throw error; + } + if (expected === actual) continue; + changed.push(entry.name); + if (update) atomicWrite(path, actual); + } + if (changed.length > 0 && !update) { + throw new Error( + `definition snapshot drift: ${changed.join(', ')}; inspect the semantic change, then run npm run check:definition-snapshots -- --update`, + ); + } + return { checked: entries.length, changed }; +} + +function main(): void { + const args = new Set(process.argv.slice(2)); + for (const arg of args) { + if (arg !== '--update') throw new Error(`unknown argument ${arg}`); + } + const result = checkDefinitionSnapshots({ update: args.has('--update') }); + console.log(`${result.checked} definition snapshots checked${ + result.changed.length > 0 ? `; ${result.changed.length} updated` : '; no drift'}`); +} + +if (process.argv[1] && pathToFileURL(process.argv[1]).href === import.meta.url) main(); diff --git a/tools/stack-bench/commands/fault-injection.ts b/tools/stack-bench/commands/fault-injection.ts new file mode 100644 index 00000000000..fc8f324d6be --- /dev/null +++ b/tools/stack-bench/commands/fault-injection.ts @@ -0,0 +1,250 @@ +#!/usr/bin/env node +// Fault injection may remove only resources owned by its lease. + +import assert from 'node:assert/strict'; +import { execFileSync, spawn } from 'node:child_process'; +import type { ChildProcess } from 'node:child_process'; +import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync } from 'node:fs'; +import { createServer } from 'node:http'; +import type { Server } from 'node:http'; +import type { AddressInfo } from 'node:net'; +import { basename, join, resolve } from 'node:path'; +import { tmpdir } from 'node:os'; +import { setTimeout as delay } from 'node:timers/promises'; + +import { createBackendLease, writeBackendLease } from '../src/runtime/backend-lease.js'; +import { killTree, pidsOnPort } from '../src/runtime/platform.js'; +import { ARTIFACT_FILE, readArtifact, readArtifactPayload } from '../src/evidence/artifacts.js'; +import { DEFAULT_BUILD_IMAGE } from '../src/composition/product-config.js'; + +import { STACK_BENCH_ROOT as ROOT, compiledEntrypoint } from '../src/package-root.js'; +const REPO = resolve(ROOT, '..', '..'); +const IMAGE = process.env.STACK_BENCH_IMAGE ?? DEFAULT_BUILD_IMAGE; +const CLI = process.env.SPACETIME_BIN ?? join(REPO, 'target', 'release', + process.platform === 'win32' ? 'spacetimedb-cli.exe' : 'spacetimedb-cli'); +const RUN_BUILD = compiledEntrypoint('container', 'run-build.js'); +interface ContainerIdentity { id: string; running: boolean; } +interface ExitResult { code: number | null; signal: NodeJS.Signals | null; } +interface FaultLeaseResources { + listenerProcesses: Array<{ pid: number; startMarker: string }>; + buildContainer: { id: string; image: string; running: boolean; removedAt?: string }; + locks: { releasedAt?: string }[]; +} +interface FaultLeaseEvidence { + runId: string; + state: string; + stoppedAt?: string; + releasedAt?: string; + resources: FaultLeaseResources; +} + +function isRecord(value: unknown): value is Record { + return value !== null && typeof value === 'object' && !Array.isArray(value); +} + +async function freePort() { + const server = createServer((_request, response) => response.end('foreign')); + await new Promise((ok, fail) => server.listen({ port: 0, host: '127.0.0.1' }, ok).once('error', fail)); + const address = server.address(); + if (!address || typeof address === 'string') throw new Error('could not allocate a TCP port'); + const port: AddressInfo['port'] = address.port; + await new Promise(ok => server.close(ok)); + return port; +} + +function inspectContainer(target: string): ContainerIdentity | null { + try { + const output = execFileSync('docker', ['inspect', '--format', + '{{.Id}} {{.State.Running}}', target], { encoding: 'utf8', stdio: 'pipe' }).trim(); + const [id, running] = output.split(/\s+/, 2); + if (!id) return null; + return { id, running: running === 'true' }; + } catch { return null; } +} + +function startContainer(name: string): ContainerIdentity { + const id = execFileSync('docker', ['run', '-d', '--init', '--name', name, + IMAGE, 'sleep', 'infinity'], { encoding: 'utf8', stdio: 'pipe' }).trim(); + assert.ok(id, `Docker did not return an id for ${name}`); + const container = inspectContainer(id); + if (!container) throw new Error(`Docker did not return a running container for ${name}`); + return container; +} + +function removeExactContainer(identity: ContainerIdentity | { id: string } | null): void { + if (!identity) return; + const current = inspectContainer(identity.id); + if (!current || current.id !== identity.id) return; + execFileSync('docker', ['rm', '-f', identity.id], { stdio: 'ignore' }); +} + +async function waitForExit(child: ChildProcess, timeoutMs: number): Promise { + return new Promise((resolveExit, reject) => { + const timeout = setTimeout(() => reject(new Error( + `benchmark runner did not exit after injected failure within ${timeoutMs}ms`)), timeoutMs); + child.once('exit', (code: number | null, signal: NodeJS.Signals | null) => { + clearTimeout(timeout); + resolveExit({ code, signal }); + }); + }); +} + +async function assertRefusesUnleasedCollision() { + const root = mkdtempSync(join(tmpdir(), 'stack-bench-container-collision-')); + const app = join(root, 'app'); + const name = `stack-bench-${basename(root)}`; + const leasePath = join(root, ARTIFACT_FILE.backendLease); + let foreign = null; + try { + mkdirSync(app, { recursive: true }); + foreign = startContainer(name); + const lease = createBackendLease({ runId: `collision-${process.pid}`, backend: 'spacetime', + track: 'fault-injection', runIndex: 0, serverUri: 'http://127.0.0.1:1', + module: `collision-${process.pid}`, dataDir: join(root, 'data') }); + lease.state = 'active'; + writeBackendLease(leasePath, lease); + + let refused = false; + try { + execFileSync(process.execPath, + [RUN_BUILD, '--app', app, '--backend', 'spacetime', '--prepare-only'], + { stdio: 'pipe', env: { ...process.env, STACK_BENCH_LEASE: leasePath, + STACK_BENCH_LEASE_TOKEN: lease.ownershipToken } }); + } catch (error: unknown) { + const childError = error instanceof Error && isRecord(error) ? error : null; + refused = childError?.status === 3 + && /refusing to adopt existing unleased container/.test(String(childError?.stderr)); + } + assert.equal(refused, true, 'launcher did not explicitly refuse an unleased same-name container'); + assert.deepEqual(inspectContainer(foreign.id), foreign, + 'collision refusal changed or stopped the foreign container'); + } finally { + removeExactContainer(foreign); + rmSync(root, { recursive: true, force: true }); + } +} + +async function main() { + assert.ok(existsSync(CLI), `local SpacetimeDB CLI is missing: ${CLI}`); + execFileSync('docker', ['image', 'inspect', IMAGE], { stdio: 'pipe' }); + await assertRefusesUnleasedCollision(); + + const root = mkdtempSync(join(tmpdir(), 'stack-bench-fault-')); + const app = join(root, 'app'); + const out = join(root, 'out'); + const markerPath = join(app, '.fault-ready.json'); + const port = await freePort(); + const uri = `http://127.0.0.1:${port}`; + const foreignName = `stack-bench-foreign-${process.pid}-${Date.now()}`; + let foreignContainer: ContainerIdentity | null = null; + let foreignServer: Server | null = null; + let bench: ChildProcess | null = null; + let marker: { lease: { runId: string; state: string; resources: FaultLeaseResources }; leasePath: string; phase: string } | null = null; + let output = ''; + + try { + mkdirSync(app, { recursive: true }); + mkdirSync(out, { recursive: true }); + foreignContainer = startContainer(foreignName); + const startedForeignServer = createServer((_request, response) => response.end('foreign')); + foreignServer = startedForeignServer; + await new Promise((ok, fail) => startedForeignServer.listen({ port: 0, host: '127.0.0.1' }, ok).once('error', fail)); + const foreignAddress = startedForeignServer.address(); + if (!foreignAddress || typeof foreignAddress === 'string') throw new Error('could not allocate foreign TCP port'); + const foreignUri = `http://127.0.0.1:${foreignAddress.port}`; + + bench = spawn(process.execPath, + [compiledEntrypoint('commands', 'bench.js'), '--backend', 'spacetime', '--track', 'loop', + '--levels', '1', '--agent-adapter', 'fault-injection', '--app', app, '--out', out, + '--url', `file:///${app.replace(/\\/g, '/')}/index.html`], + { env: { ...process.env, STACK_BENCH_STDB_URI: uri, STACK_BENCH_IMAGE: IMAGE, + SPACETIME_BIN: CLI }, + stdio: ['ignore', 'pipe', 'pipe'], windowsHide: true }); + const collect = (chunk: Buffer): void => { output = (output + chunk.toString()).slice(-256 * 1024); }; + bench.stdout?.on('data', collect); + bench.stderr?.on('data', collect); + const exited = await waitForExit(bench, 300_000); + assert.notEqual(exited.code, 0, 'injected coding-agent failure unexpectedly exited zero'); + assert.ok(existsSync(markerPath), `fault marker was not written before failure:\n${output}`); + const markerValue: unknown = JSON.parse(readFileSync(markerPath, 'utf8')); + if (!isRecord(markerValue) || !isRecord(markerValue.lease) || !isRecord(markerValue.lease.resources) + || typeof markerValue.leasePath !== 'string' || typeof markerValue.phase !== 'string' + || typeof markerValue.lease.runId !== 'string' || typeof markerValue.lease.state !== 'string') { + throw new Error('fault marker is invalid'); + } + const markerResources = markerValue.lease.resources; + if (!Array.isArray(markerResources.listenerProcesses) || !isRecord(markerResources.buildContainer) + || typeof markerResources.buildContainer.id !== 'string') throw new Error('fault marker resources are invalid'); + marker = { phase: markerValue.phase, leasePath: markerValue.leasePath, + lease: { runId: markerValue.lease.runId, state: markerValue.lease.state, + resources: { listenerProcesses: markerResources.listenerProcesses.filter((item): item is { + pid: number; startMarker: string } => isRecord(item) && typeof item.pid === 'number' + && typeof item.startMarker === 'string'), buildContainer: { + id: markerResources.buildContainer.id, image: String(markerResources.buildContainer.image ?? ''), + running: markerResources.buildContainer.running === true }, locks: [] } } }; + assert.equal(marker.phase, 'restart-stopped', + 'fault was not injected inside the backend restart window'); + assert.equal(marker.lease.state, 'restarting'); + assert.match(marker.lease.resources.buildContainer.image, /^sha256:[0-9a-f]{64}$/, + 'build container lease did not record an immutable image id'); + + const evidencePath = join(out, ARTIFACT_FILE.backendLease); + assert.ok(existsSync(evidencePath), `teardown did not preserve lease evidence:\n${output}`); + const evidence = readArtifactPayload(evidencePath, { expectedKind: 'backend_lease_evidence' }); + const preflight = readArtifact(join(out, ARTIFACT_FILE.preflight), + { expectedKind: 'preflight' }); + assert.equal(preflight.payload.ok, true, 'paid-run preflight did not pass'); + assert.equal(preflight.attempt.parentId, marker.lease.runId, + 'preflight evidence is not attached to the run it admitted'); + assert.equal(evidence.runId, marker.lease.runId); + assert.equal(evidence.state, 'released', 'benchmark lease did not reach its terminal state'); + assert.ok(evidence.stoppedAt, 'benchmark-owned SpacetimeDB host has no stop evidence'); + assert.ok(evidence.releasedAt, 'benchmark lease has no release evidence'); + assert.deepEqual(evidence.resources.listenerProcesses, []); + assert.equal(evidence.resources.buildContainer.running, false, + 'benchmark-owned build container was not marked removed'); + assert.ok(evidence.resources.buildContainer.removedAt); + assert.ok(evidence.resources.locks.every(lock => lock.releasedAt), + 'one or more resource locks were not released'); + assert.equal(inspectContainer(marker.lease.resources.buildContainer.id), null, + 'benchmark-owned build container survived fatal cleanup'); + assert.equal(pidsOnPort(port).length, 0, 'benchmark-owned listener survived fatal cleanup'); + assert.equal(existsSync(marker.leasePath), false, 'private runtime lease was not removed'); + + assert.equal((await fetch(foreignUri)).status, 200, + 'foreign listener was disturbed by benchmark cleanup'); + assert.deepEqual(inspectContainer(foreignContainer.id), foreignContainer, + 'foreign container was changed or removed by benchmark cleanup'); + + console.log(JSON.stringify({ ok: true, injectedAt: 'restart-stopped-before-replacement', + benchmarkHostStopped: true, benchmarkContainerRemoved: true, locksReleased: true, + privateLeaseRemoved: true, foreignListenerSurvived: true, + foreignContainerSurvived: true, unleasedCollisionRefused: true, + immutableImagePinned: true }, null, 2)); + } finally { + if (bench?.exitCode === null) { + killTree(bench.pid); + await delay(500); + } + if (marker?.lease?.resources?.buildContainer) { + removeExactContainer(marker.lease.resources.buildContainer); + } + for (const identity of marker?.lease?.resources?.listenerProcesses ?? []) { + if (pidsOnPort(port).includes(String(identity.pid))) killTree(identity.pid); + } + if (foreignServer) { + const server = foreignServer; + // The verification fetch uses a keep-alive connection. Waiting on + // close() alone can hold CI open until Undici retires that socket. + server.closeAllConnections(); + await new Promise((ok, fail) => server.close(error => error ? fail(error) : ok())); + } + removeExactContainer(foreignContainer); + rmSync(root, { recursive: true, force: true }); + } +} + +main().catch(error => { + console.error(error.stack ?? error.message); + process.exitCode = 1; +}); diff --git a/tools/stack-bench/commands/job-cli.ts b/tools/stack-bench/commands/job-cli.ts new file mode 100644 index 00000000000..e5d0233919f --- /dev/null +++ b/tools/stack-bench/commands/job-cli.ts @@ -0,0 +1,64 @@ +#!/usr/bin/env node +import { readFileSync } from 'node:fs'; +import { resolve } from 'node:path'; +import { pathToFileURL } from 'node:url'; +import { parseArgs } from 'node:util'; +import { cancelExecutionJob, listExecutionJobs, readExecutionJob, + submitExecutionJob, workExecutionJob } from '../src/campaigns/execution-jobs.js'; +import { runExecutionWorker } from '../src/campaigns/execution-worker.js'; +import { prepareRun, runSetupCatalog, submitPreparedRun } from '../src/campaigns/run-setup.js'; + +export async function jobCommand(argv: string[], env: NodeJS.ProcessEnv = process.env) { + const { values, positionals } = parseArgs({ args: argv, allowPositionals: true, options: { + results: { type: 'string' }, host: { type: 'string' }, after: { type: 'string' }, + limit: { type: 'string' }, concurrency: { type: 'string' }, + } }); + const [command, argument] = positionals; + if (argv[0] !== command) throw new Error('put the job command before its options'); + if (positionals.length > 2) throw new Error('unexpected job arguments'); + const results = resolve(values.results ?? env.STACK_BENCH_RESULTS_DIR ?? 'results'); + if (command === 'options' && !argument) return runSetupCatalog(results, env); + if (command === 'prepare' && argument) return prepareRun(results, + JSON.parse(readFileSync(argument === '-' ? 0 : argument, 'utf8')), env); + if (command === 'start' && argument) { + const host = values.host ?? env.STACK_BENCH_HOST_ID; + if (!host) throw new Error('job start requires --host or STACK_BENCH_HOST_ID'); + const job = submitPreparedRun(results, JSON.parse(readFileSync(argument === '-' ? 0 : argument, 'utf8')), env); + console.log(JSON.stringify({ jobId: job.id, campaignKey: `job-${job.id}` })); + return jobCommand(['work', job.id, '--results', results, '--host', host], env); + } + if (command === 'submit' && argument) return submitExecutionJob(results, + JSON.parse(readFileSync(argument === '-' ? 0 : argument, 'utf8'))); + if (command === 'status' && argument) return readExecutionJob(results, argument); + if (command === 'cancel' && argument) { + cancelExecutionJob(results, argument); return readExecutionJob(results, argument); + } + if (command === 'list' && !argument) return listExecutionJobs(results, + { after: values.after, limit: values.limit === undefined ? undefined : Number(values.limit) }); + if ((command === 'work' && argument) || (command === 'worker' && !argument)) { + const host = values.host ?? env.STACK_BENCH_HOST_ID; + if (!host) throw new Error('job work/worker requires --host or STACK_BENCH_HOST_ID'); + const controller = new AbortController(); + const stop = () => controller.abort(); + process.on('SIGTERM', stop); process.on('SIGINT', stop); + try { + if (command === 'worker') { + await runExecutionWorker(results, host, { env, signal: controller.signal, + concurrency: Number(values.concurrency) }); + return { status: 'stopped' as const }; + } + return await workExecutionJob(results, argument!, host, { env, signal: controller.signal }); + } + finally { process.off('SIGTERM', stop); process.off('SIGINT', stop); } + } + throw new Error('use job options, prepare , start --host , submit , list, status , cancel , work --host , or worker --host --concurrency '); +} + +if (import.meta.url === pathToFileURL(process.argv[1] ?? '').href) { + jobCommand(process.argv.slice(2)).then(result => { + console.log(JSON.stringify(result, null, 2)); + if ('status' in result && result.status === 'failed') process.exitCode = 1; + }).catch((error: unknown) => { + console.error(error instanceof Error ? error.message : String(error)); process.exitCode = 1; + }); +} diff --git a/tools/stack-bench/commands/leak-audit.ts b/tools/stack-bench/commands/leak-audit.ts new file mode 100644 index 00000000000..a4f4580c74b --- /dev/null +++ b/tools/stack-bench/commands/leak-audit.ts @@ -0,0 +1,325 @@ +#!/usr/bin/env node +// Use the recorded cwd as the app boundary; transcript folder names are not authority. + +import { readdirSync, readFileSync, existsSync } from 'node:fs'; +import { join, posix, resolve } from 'node:path'; +import { homedir } from 'node:os'; +import { pathToFileURL } from 'node:url'; +import { parseArgs } from 'node:util'; +import { CODING_CONTAINER_APP_ROOT } from '../src/runtime/coding-container-policy.js'; +import { transcriptDirectories } from '../src/agents/transcript-archive.js'; +import { codexTranscriptDirectory } from '../src/agents/codex-protocol.js'; + +const norm = (value: unknown): string => String(value ?? '') + .replace(/\\/g, '/').replace(/^["']|["']$/g, '').toLowerCase(); + +// Ignore dependencies, build output, and this session's CLI task output. +const IGNORE = /node_modules|\.git[/\\]|package-lock\.json|\/dist\/|\.map$|[/\\]temp[/\\]claude[/\\].*[/\\]tasks[/\\]/; + +// Commands that pull file contents into context. +const READER = /(?:^|[;&|]\s*)(?:cat|head|tail|less|more|type|grep|rg|ack|find|ls\s+-\w*l|sed\s+-n|awk)\s+([^;&|]+)/g; + +// Network targets in a shell command: any URL, and a raw socket target. A +// A verified attempt namespace owns its loopback ports, including temporary +// test servers. Shared namespaces require exact endpoints. Internet targets +// are recorded, not judged. +const URL_TARGET = /https?:\/\/([^\s/'"`]+)/gi; +const SOCKET_TARGET = /(?:^|[;&|]\s*)(?:nc|ncat|netcat)\s+(?:-\S+\s+)*([\w.-]+)\s+(\d{2,5})\b/g; +const LOCAL_HOST = /^(?:127\.\d+\.\d+\.\d+|localhost|0\.0\.0\.0|\[::1\]|host\.docker\.internal|10\.\d+\.\d+\.\d+|172\.(?:1[6-9]|2\d|3[01])\.\d+\.\d+|192\.168\.\d+\.\d+)$/i; +const LOOPBACK_HOST = /^(?:127\.\d+\.\d+\.\d+|localhost|0\.0\.0\.0|\[::1\])$/i; + +export interface AuditNetworkContext { + ownEndpoints?: readonly string[]; + isolatedLoopback?: boolean; +} + +export interface NetworkTarget { + host: string; + port: number | null; +} + +export function networkTargetsFromBash(command: unknown): NetworkTarget[] { + const targets: NetworkTarget[] = []; + const text = String(command ?? ''); + for (const match of text.matchAll(URL_TARGET)) { + const authority = (match[1] ?? '').replace(/^[^@]*@/, ''); + const port = authority.match(/:(\d{1,5})$/)?.[1]; + targets.push({ host: authority.replace(/:\d{1,5}$/, ''), port: port ? Number(port) : null }); + } + for (const match of text.matchAll(SOCKET_TARGET)) { + targets.push({ host: match[1] ?? '', port: Number(match[2]) }); + } + return targets; +} + +const endpointHost = (host: string): string => /^(?:127\.0\.0\.1|0\.0\.0\.0|localhost|\[::1\])$/i.test(host) + ? 'localhost' : host.toLowerCase(); +const endpointKey = (target: NetworkTarget): string => `${endpointHost(target.host)}:${target.port}`; + +const networkKind = (target: NetworkTarget, ownEndpoints: ReadonlySet, isolatedLoopback: boolean): string | null => { + if (isolatedLoopback && LOOPBACK_HOST.test(target.host)) return null; + if (ownEndpoints.has(endpointKey(target))) return null; + if (!LOCAL_HOST.test(target.host)) return 'network (internet)'; + return 'NETWORK / OTHER RUN'; +}; + +const CLASSES: Array = [ + [/[/\\]stack-bench(?:[/\\]|$)/, 'GRADER / TEST SPECS'], + [/\.claude[/\\]projects.*memory|[/\\]memory[/\\].*\.md$/, 'BENCHMARK NOTES'], + [/scenarios[/\\].*\.json|grade\.(?:js|ts)|mutation|check-scenarios/, 'GRADER / TEST SPECS'], + [/contracts[/\\].*\.json|appendix-\d+\.md|walk\.(?:js|ts)|lint\.(?:js|ts)/, 'CONTRACT / LINTER'], + [/prompts[/\\]|test-plans[/\\]|GRADING|RUBRIC/, 'PROMPTS / RUBRIC'], + [/[/\\]skills[/\\]/, 'skill docs (intended)'], + [/backends[/\\].*\.md|CLAUDE\.md|README/, 'setup docs (intended)'], +]; +const classify = (path: string): string => CLASSES.find(([pattern]) => pattern.test(path))?.[1] + ?? 'other'; + +// The shallowest recorded cwd is the app boundary when --app is absent. +function sessionCwd(lines: string[]): string | null { + const seen = new Set(); + for (const l of lines) { + const m = l.match(/"cwd":"((?:[^"\\]|\\.)*)"/); + if (m?.[1]) seen.add(norm(m[1].replace(/\\\\/g, '/'))); + } + if (!seen.size) return null; + return [...seen].sort((a, b) => a.split('/').length - b.split('/').length || a.length - b.length)[0] + ?? null; +} + +export function pathsFromBash(command: unknown): string[] { + const out: string[] = []; + for (const match of String(command).matchAll(READER)) { + const argumentsText = match[1]; + if (!argumentsText) continue; + for (const tokRaw of argumentsText.split(/\s+/)) { + const t = tokRaw.replace(/^["']|["']$/g, ''); + if (!t || t.startsWith('-')) continue; + if (/[*?]/.test(t) || /\//.test(t) || /\\/.test(t) || /\.\w+$/.test(t)) out.push(t); + } + } + return out; +} + +// Count file-tool reads only after their result confirms success. +// Bash reads count unless the command fails. +interface AuditHit { + path: string; + via: string; + kind: string; + unresolved?: boolean; +} + +interface PendingRead { + paths: string[]; + network: Array<{ path: string; kind: string }>; + via: string; +} + +interface TranscriptAudit { + file: string; + cwd: string | null; + fileTool: number; + bashReads: number; + hits: AuditHit[]; + refused: AuditHit[]; +} + +interface AuditResult extends TranscriptAudit { + root: string; +} + +interface TranscriptContent { + type?: string; + name?: string; + id?: string; + tool_use_id?: string; + is_error?: boolean; + input?: { file_path?: string; path?: string; pattern?: string; command?: string }; +} + +// Feed both CLIs through the same path, network, and refusal checks. +function transcriptContent(event: Record): TranscriptContent[] { + const message = event.message as { content?: TranscriptContent[] } | undefined; + if (Array.isArray(message?.content)) return message.content; + if (event.type !== 'item.started' && event.type !== 'item.completed') return []; + const item = event.item as { id?: string; type?: string; command?: string; + aggregated_output?: string; exit_code?: number; status?: string; + changes?: { path: string }[] } | undefined; + if (!item?.id) return []; + const content: TranscriptContent[] = []; + if (item.type === 'command_execution') { + // Codex records the shell launcher around the command. + const command = (item.command ?? '').replace(/^(?:\/\S+\/)?(?:bash|sh|zsh)\s+-[a-z]*c\s+(['"])([\s\S]*)\1$/, '$2'); + content.push({ type: 'tool_use', id: item.id, name: 'Bash', input: { command } }); + } else if (item.type === 'file_change') { + for (const [index, change] of (item.changes ?? []).entries()) { + content.push({ type: 'tool_use', id: `${item.id}:${index}`, name: 'Edit', + input: { file_path: change.path } }); + } + } + if (event.type === 'item.completed') { + // Output can contain a successful read before a later command fails. + const blocked = item.status === 'failed' && !item.aggregated_output?.trim(); + for (const call of [...content]) content.push({ type: 'tool_result', + tool_use_id: call.id, is_error: blocked }); + } + return content; +} + +export function auditTranscript(file: string, boundary: string | null, + { ownEndpoints = [], isolatedLoopback = false }: AuditNetworkContext = {}): TranscriptAudit { + const endpoints = new Set(ownEndpoints.map(endpoint => { + const url = new URL(`http://${endpoint}`); + return endpointKey({ host: url.hostname, port: Number(url.port || 80) }); + })); + const lines = readFileSync(file, 'utf8').split('\n').filter(Boolean); + // Container transcripts use /app; --app is its host path. + const recorded = sessionCwd(lines); + const cwd = recorded === CODING_CONTAINER_APP_ROOT ? recorded : (boundary ?? recorded); + const hits: AuditHit[] = []; + const refused: AuditHit[] = []; + const pending = new Map(); + let fileTool = 0, bashReads = 0; + + for (const line of lines) { + let event: Record; + try { event = JSON.parse(line) as typeof event; } catch { continue; } + const c = transcriptContent(event); + for (const p of c) { + if (p.type === 'tool_result' && p.tool_use_id && pending.has(p.tool_use_id)) { + const completed = pending.get(p.tool_use_id ?? ''); + if (!completed) continue; + const { paths, network, via } = completed; + pending.delete(p.tool_use_id ?? ''); + const blocked = p.is_error === true; + for (const n of paths) (blocked ? refused : hits).push({ path: n, via, kind: classify(n) }); + for (const target of network) (blocked ? refused : hits).push({ ...target, via: `${via} network attempt` }); + continue; + } + if (p.type !== 'tool_use') continue; + const cand = []; + if (/^(Read|Grep|Glob|NotebookRead|Edit)$/.test(p.name ?? '')) { + fileTool++; + cand.push(p.input?.file_path ?? p.input?.path ?? p.input?.pattern ?? ''); + } else if (p.name === 'Bash') { + const found = pathsFromBash(p.input?.command ?? ''); + bashReads += found.length; + cand.push(...found); + } + const paths = []; + const network: Array<{ path: string; kind: string }> = []; + if (p.name === 'Bash') { + for (const target of networkTargetsFromBash(p.input?.command ?? '')) { + const kind = networkKind(target, endpoints, isolatedLoopback); + if (kind) network.push({ path: `${target.host}${target.port === null ? '' : `:${target.port}`}`, kind }); + } + } + for (const raw of cand) { + let n = norm(raw); + if (!n || IGNORE.test(n)) continue; + // The CLI keeps auto-memory for the session's OWN project dir. A build + // A session may read its own memory, never another project's memory. + if (cwd && /[/\\]projects[/\\][^/\\]+[/\\]memory[/\\]/.test(n) + && n.includes(cwd.replace(/[\\/:]/g, '-'))) continue; + const absolute = /^[a-z]:/.test(n) || n.startsWith('/'); + if (!absolute && cwd) n = `${cwd}/${n.replace(/^\.\//, '')}`; + n = posix.normalize(n); + const privateHarnessPath = cwd + && (n === `${cwd}/stack-bench` || n.startsWith(`${cwd}/stack-bench/`)); + if (!privateHarnessPath && !absolute && !cwd) continue; + if (!privateHarnessPath && cwd && (n === cwd || n.startsWith(`${cwd}/`))) continue; + paths.push(n); + } + if ((paths.length || network.length) && p.id && p.name) { + pending.set(p.id, { paths, network, via: p.name }); + } + } + } + // A call whose result never arrived (session cut short) is unresolved, and + // unresolved is not innocent: count it. + for (const { paths, network, via } of pending.values()) { + for (const n of paths) hits.push({ path: n, via, kind: classify(n), unresolved: true }); + for (const target of network) hits.push({ ...target, via: `${via} network attempt`, unresolved: true }); + } + + return { file, cwd, fileTool, bashReads, hits, refused }; +} + +function main(): void { + const { values } = parseArgs({ args: process.argv.slice(2), options: { + app: { type: 'string' }, dir: { type: 'string' }, json: { type: 'boolean' }, + 'own-endpoints': { type: 'string' }, + 'isolated-loopback': { type: 'boolean' }, + } }); + const ownEndpoints = (values['own-endpoints'] ?? '').split(',').filter(Boolean); + const requestedApp = values.app; + const requestedDirectory = values.dir; + if (requestedApp && requestedDirectory) throw new Error('--app and --dir cannot be used together'); + const roots = requestedApp ? transcriptDirectories(requestedApp) + : requestedDirectory ? [resolve(requestedDirectory)] + : [join(homedir(), '.claude', 'projects')]; + // When the caller names the app directory, that is the boundary. Do not + // infer it from a transcript folder name. + const appBoundary = requestedApp ? norm(resolve(requestedApp)) : null; + const results: AuditResult[] = []; +for (const root of roots) { + if (!existsSync(root)) continue; + const stack = [root]; + while (stack.length) { + const d = stack.pop(); + if (!d) continue; + for (const e of readdirSync(d, { withFileTypes: true })) { + const p = join(d, e.name); + if (e.isDirectory()) { + // Codex native rollouts are agent-writable; audit controller event logs only. + if (!/node_modules/.test(p) + && !(requestedApp && root === codexTranscriptDirectory(requestedApp))) stack.push(p); + continue; + } + if (!/\.jsonl$/.test(e.name)) continue; + // Include transcripts from the main session and its subagents. + if (!/transcript|^agent-|^[0-9a-f-]{36}\.jsonl$|\.events\.jsonl$/.test(e.name)) continue; + results.push({ ...auditTranscript(p, appBoundary, { ownEndpoints, + isolatedLoopback: values['isolated-loopback'] === true }), root }); + } + } +} + +if (values.json) { + console.log(JSON.stringify(results, null, 2)); + return; +} + +const label = (file: string): string => file.replace(/\\/g, '/') + .split('/').slice(-3).join('/').slice(0, 62); +console.log('\nBuilds that read outside their own directory'); +console.log('(counts BOTH file tools and Bash cat/grep/find; boundary = the session\'s own cwd)\n'); + +let clean = 0; +for (const r of results.sort((a, b) => b.hits.length - a.hits.length)) { + if (!r.cwd) { console.log(` ?? ${label(r.file)} — no cwd recorded, cannot judge`); continue; } + if (!r.hits.length) { + clean++; + // Blocked attempts are worth printing: they are the sandbox doing its job, + // and they say which paths a build still goes looking for. + if (r.refused?.length) { + const kinds = [...new Set(r.refused.map(h => h.kind))].join(', '); + console.log(` ${label(r.file)}\n clean — ${r.refused.length} attempt(s) BLOCKED by the sandbox (${kinds})`); + } + continue; + } + const byKind: Record = {}; + for (const h of r.hits) (byKind[h.kind] ??= []).push(h.path); + console.log(` ${label(r.file)}`); + console.log(` cwd: ...${r.cwd.slice(-52)} (${r.fileTool} file-tool, ${r.bashReads} bash reads)`); + for (const [k, v] of Object.entries(byKind).sort((a, b) => b[1].length - a[1].length)) { + const example = [...new Set(v)][0] ?? ''; + console.log(` ${String(v.length).padStart(3)}x ${k.padEnd(22)} ${example.split('/').slice(-2).join('/')}`); + } +} +console.log(`\n ${clean} transcript(s) read nothing outside their directory.`); +console.log(` ${results.length} transcript(s) examined.\n`); +} + +if (process.argv[1] && pathToFileURL(process.argv[1]).href === import.meta.url) main(); diff --git a/tools/stack-bench/commands/null-control.ts b/tools/stack-bench/commands/null-control.ts new file mode 100644 index 00000000000..3631b149b9e --- /dev/null +++ b/tools/stack-bench/commands/null-control.ts @@ -0,0 +1,282 @@ +#!/usr/bin/env node +// Grade the real validated production scenarios against a reachable app that +// implements nothing. Every point-bearing criterion must conclusively fail. + +import { execFile } from 'node:child_process'; +import { createServer } from 'node:http'; +import type { Server } from 'node:http'; +import type { AddressInfo } from 'node:net'; +import { mkdirSync, mkdtempSync, rmSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { basename, join, relative, resolve } from 'node:path'; +import { pathToFileURL } from 'node:url'; +import { parseArgs as parseNodeArgs } from 'node:util'; +import { chromium, type BrowserServer } from 'playwright'; +import { readArtifactPayload, writeRunJson } from '../src/evidence/artifacts.js'; +import { calibrationQualificationIdentity, calibrationQualificationRelease, + resolveCalibrationForRelease } from '../src/composition/calibration-compiler.js'; +import { qualificationScopeIdentity } from '../src/composition/qualification-scope.js'; +import { writeQualificationSnapshot } from '../src/composition/qualification-slices.js'; +import { analyseNullReports } from '../src/evidence/null-control-analysis.js'; +import { resolveRecipeRelease } from '../src/composition/recipe-release.js'; +import { resolveRecipeSelection } from '../src/composition/recipe-selection.js'; +import { isDeclaredLevel, listTracks, loadTrack, suitesFor } from '../src/composition/tracks.js'; +import { controllerRunner } from '../src/runtime/runner-environment.js'; +import type { CalibrationPlan } from '../src/composition/calibration-compiler.js'; +import type { RecipeBinding } from '../src/composition/recipe-release.js'; +import type { Track } from '../src/composition/tracks.js'; + +import { STACK_BENCH_ROOT as ROOT, compiledEntrypoint } from '../src/package-root.js'; +const GRADE = compiledEntrypoint('grader', 'grade.js'); +const NULL_CONTROL_WORKERS = 4; + +interface NullControlArgs { + tracks: string[]; + level: number | null; + recipe?: string; + out?: string; + audit: boolean; + parentAttemptId?: string; + selectedChecks: string[]; +} + +export function parseNullControlArgs(argv: string[]): NullControlArgs { + const { values } = parseNodeArgs({ args: argv.slice(2), options: { + track: { type: 'string' }, level: { type: 'string' }, recipe: { type: 'string' }, + out: { type: 'string' }, audit: { type: 'boolean' }, 'parent-attempt-id': { type: 'string' }, + 'selected-check': { type: 'string', multiple: true }, + } }); + const args: NullControlArgs = { + tracks: values.track?.split(',').filter(Boolean) ?? listTracks(), + level: values.level === undefined ? null : Number(values.level), audit: values.audit ?? false, + recipe: values.recipe, out: values.out, parentAttemptId: values['parent-attempt-id'], + selectedChecks: values['selected-check'] ?? [], + }; + if (args.level !== null && (!Number.isInteger(args.level) || args.level < 1)) { + throw new Error('--level must be a positive integer'); + } + if (args.level !== null && args.tracks.length !== 1) { + throw new Error('--level requires exactly one --track'); + } + if (args.recipe && args.level === null) throw new Error('--recipe requires --level'); + if (args.selectedChecks.length && args.level === null) throw new Error('--selected-check requires --level'); + return args; +} + +function runGrade(argv: string[], timeoutMs = 300_000): Promise<{ stdout: string; stderr: string }> { + return new Promise((resolve, reject) => { + execFile(process.execPath, [GRADE, ...argv], { + encoding: 'utf8', maxBuffer: 32 * 1024 * 1024, timeout: timeoutMs, + }, (error, stdout, stderr) => { + if (error) { + error.message = `grader failed: ${error.message}\n${stdout}\n${stderr}`; + reject(error); + } else resolve({ stdout, stderr }); + }); + }); +} + +export function nullControlSuites(track: Track, selectedLevel: number | null = null, + binding: RecipeBinding | null = null) { + if (selectedLevel !== null && !isDeclaredLevel(track, selectedLevel)) { + throw new Error(`L${selectedLevel} is not declared for ${track.name}`); + } + if (binding) { + if (selectedLevel === null) throw new Error('recipe-bound null control requires one level'); + if (!Array.isArray(binding.execution) || !binding.execution.length) { + throw new Error('recipe-bound null control requires a typed execution plan'); + } + const executionIds = new Set(); + const mappedKeys = new Set(); + const suites = binding.execution.map(execution => { + if (executionIds.has(execution.id)) { + throw new Error(`recipe-bound null control repeats execution ${execution.id}`); + } + executionIds.add(execution.id); + const checks = binding.release.checkCatalog.filter(check => check.executionId === execution.id); + if (!checks.length) { + throw new Error(`recipe-bound null control execution ${execution.id} maps no checks`); + } + for (const check of checks) { + if (mappedKeys.has(check.stableKey)) { + throw new Error(`recipe-bound null control maps check ${check.stableKey} more than once`); + } + mappedKeys.add(check.stableKey); + } + return { id: execution.id, spec: resolve(track.dir, execution.source ?? ''), + level: selectedLevel, checks }; + }); + const missing = binding.release.checkCatalog + .filter(check => !mappedKeys.has(check.stableKey)).map(check => check.stableKey); + if (missing.length) { + throw new Error(`recipe-bound null control leaves checks unmapped: ${missing.join(', ')}`); + } + return suites; + } + const seen = new Set(); + const suites = []; + const levels = selectedLevel === null + ? Array.from({ length: track.validatedThrough }, (_, index) => index + 1) + : [selectedLevel]; + for (const level of levels) { + for (const suite of suitesFor(track, level)) { + if (seen.has(suite.spec)) continue; + seen.add(suite.spec); + suites.push({ ...suite, level }); + } + } + return suites; +} + +export function selectNullQualificationBinding(binding: RecipeBinding, calibration: CalibrationPlan): RecipeBinding { + const selected = calibrationQualificationRelease(calibration, binding.release, binding.execution); + return { ...binding, release: selected.release, execution: selected.execution }; +} + +export function createNullQualification(binding: RecipeBinding, calibration: CalibrationPlan, + selectedChecks: string[] = []) { + let selectedBinding = selectNullQualificationBinding(binding, calibration); + if (selectedChecks.length) { + const selected = calibrationQualificationRelease({ qualification: { checks: selectedChecks } }, + selectedBinding.release, selectedBinding.execution); + selectedBinding = { ...selectedBinding, ...selected }; + } + const selection = resolveRecipeSelection(selectedBinding.release, { + checkKeys: selectedBinding.release.checkCatalog.map(check => check.stableKey), + }); + return { + binding: selectedBinding, + calibration, + identity: calibrationQualificationIdentity(calibration), + selectionSha256: selection.sha256, + }; +} + +async function listen(server: Server): Promise { + await new Promise((resolve, reject) => { + server.once('error', reject); + server.listen({ port: 0, host: '127.0.0.1' }, () => resolve()); + }); + return (server.address() as AddressInfo).port; +} + +async function main() { + const args = parseNullControlArgs(process.argv); + const nullAttemptId = `null-control-${new Date().toISOString().replace(/[:.]/g, '-')}`; + const work = mkdtempSync(join(tmpdir(), 'stack-bench-null-')); + const app = join(work, 'app'); + const reportsDir = join(work, 'reports'); + mkdirSync(app, { recursive: true }); + mkdirSync(reportsDir, { recursive: true }); + + // Root navigation succeeds, proving the browser and server are healthy. All + // application/API behavior is absent: non-navigation requests get 404. + const server = createServer((request, response) => { + if (request.method === 'GET' && (request.url === '/' || request.headers.accept?.includes('text/html'))) { + response.writeHead(200, { 'content-type': 'text/html; charset=utf-8' }); + response.end('Null control'); + } else { + response.writeHead(404, { 'content-type': 'application/json' }); + response.end('{"error":"not implemented"}'); + } + }); + + const started = Date.now(); + const suiteReports = []; + let qualification: ReturnType | null = null; + let browserServer: BrowserServer | undefined; + try { + const port = await listen(server); + const url = `http://127.0.0.1:${port}`; + // This command owns the empty page; it has no generated app or attempt lease. + browserServer = await chromium.launchServer({ headless: true, host: '127.0.0.1' }); + const browserEndpoint = browserServer.wsEndpoint(); + for (const trackName of args.tracks) { + const track = loadTrack(trackName); + let binding: RecipeBinding | null = null; + if (args.level !== null) { + binding = resolveRecipeRelease(track, args.level, args.recipe); + if (!binding) throw new Error(`${trackName} L${args.level} has no recipe release`); + const calibration = resolveCalibrationForRelease(binding.release, + { trackRoot: track.dir, stackBenchRoot: ROOT, alias: `L${args.level}` }); + if (!calibration) throw new Error(`${trackName} L${args.level} has no calibration`); + qualification = createNullQualification(binding, calibration, args.selectedChecks); + binding = qualification.binding; + } + const selectedSuites = nullControlSuites(track, args.level, binding); + const resolvedRecipe = binding?.release.id ?? args.recipe; + for (let index = 0; index < selectedSuites.length; index += NULL_CONTROL_WORKERS) { + const reports = await Promise.all(selectedSuites + .slice(index, index + NULL_CONTROL_WORKERS).map(async suite => { + const reportPath = join(reportsDir, + `${trackName}-l${suite.level}-${suite.id.replaceAll('@', '-')}.json`); + console.log(`${trackName} L${suite.level} ${suite.id} (${basename(suite.spec)})`); + await runGrade(['--url', url, '--level', String(suite.level), '--spec', suite.spec, + '--backend', 'postgres', '--track', trackName, '--app', app, '--out', reportPath, + '--null-control', + '--browser-ws-endpoint', browserEndpoint, + '--parent-attempt-id', nullAttemptId, + ...(resolvedRecipe ? ['--recipe', resolvedRecipe] : []), + ...(binding ? ['--expected-recipe-sha256', binding.release.contentSha256] : []), + ...(qualification ? ['--selection-sha256', qualification.selectionSha256] : []), + ...(('checks' in suite ? suite.checks : []) ?? []) + .flatMap(check => ['--selected-check', check.stableKey])]); + const report = readArtifactPayload(reportPath, { expectedKind: 'grade' }); + console.log(`${suite.id}: ${report.total}/${report.max}`); + return { track: trackName, level: suite.level, id: suite.id, + scenario: relative(track.dir, suite.spec).replaceAll('\\', '/'), report }; + })); + suiteReports.push(...reports); + } + } + + const analysis = analyseNullReports(suiteReports); + const artifact = { + id: nullAttemptId, + kind: 'null_control', + startedAt: new Date(started).toISOString(), + completedAt: new Date().toISOString(), + parentAttemptId: args.parentAttemptId ?? null, + identities: qualification ? { + recipe: { id: qualification.binding.release.id, + sha256: qualification.binding.release.contentSha256 }, + calibration: { id: qualification.identity.id, + sha256: qualification.identity.contentSha256 }, + } : undefined, + durationMs: Date.now() - started, + runner: controllerRunner(), + ...(qualification ? { qualificationScope: qualificationScopeIdentity({ + kind: 'null', release: qualification.binding.release, stackBenchRoot: ROOT, + }) } : {}), + tracks: args.tracks, + ...analysis, + }; + const outputPath = resolve(args.out ?? join(ROOT, 'results', `${artifact.id}.json`)); + writeRunJson(outputPath, artifact); + if (qualification) writeQualificationSnapshot(`${outputPath}.inputs.json`, + qualification.binding.recipePath, qualification.calibration, ROOT); + console.log(JSON.stringify({ + id: artifact.id, + kind: artifact.kind, + durationMs: artifact.durationMs, + tracks: artifact.tracks, + ok: artifact.ok, + summary: artifact.summary, + artifact: outputPath, + }, null, 2)); + if (!analysis.ok && !args.audit) process.exitCode = 1; + } finally { + try { await browserServer?.close(); } + finally { + await new Promise(resolve => server.close(resolve)); + rmSync(work, { recursive: true, force: true }); + } + } +} + +if (process.argv[1] && pathToFileURL(resolve(process.argv[1])).href === import.meta.url) { + main().catch(error => { + console.error(error.stack ?? error.message); + process.exitCode = 2; + }); +} diff --git a/tools/stack-bench/commands/pack-budget.ts b/tools/stack-bench/commands/pack-budget.ts new file mode 100644 index 00000000000..51c3ffe8b12 --- /dev/null +++ b/tools/stack-bench/commands/pack-budget.ts @@ -0,0 +1,81 @@ +#!/usr/bin/env node + +import { existsSync } from 'node:fs'; +import { dirname, relative, resolve } from 'node:path'; +import { pathToFileURL } from 'node:url'; +import { parseArgs } from 'node:util'; + +import { artifactPayload, recipeArtifactIdentities, writeArtifact } from '../src/evidence/artifacts.js'; +import { resolveCalibrationForRelease } from '../src/composition/calibration-compiler.js'; +import { loadPackBudgetEvidence, PACK_BUDGET_POLICY, recommendPackBudgets } + from '../src/composition/pack-budget.js'; +import { resolveRecipeRelease } from '../src/composition/recipe-release.js'; +import { isDeclaredLevel, listTracks, loadTrack } from '../src/composition/tracks.js'; + +interface PackBudgetArgs { + command: 'recommend'; + track: string; + level: number; + evidence: string[]; + out: string; + recipe?: string; +} + +const USAGE = 'usage: pack-budget.js recommend --track --level ' + + '[--recipe ] --evidence [--evidence ...] ' + + '--out '; + +export function parsePackBudgetArgs(argv: string[]): PackBudgetArgs { + const [command, ...options] = argv.slice(2); + const { values } = parseArgs({ args: options, options: { + track: { type: 'string' }, + level: { type: 'string' }, + recipe: { type: 'string' }, + evidence: { type: 'string', multiple: true }, + out: { type: 'string' }, + } }); + const level = Number(values.level); + const evidence = (values.evidence ?? []).map(path => resolve(path)); + if (command !== 'recommend' || !values.track || !Number.isInteger(level) || level < 1 + || !evidence.length || !values.out) throw new Error(USAGE); + if (new Set(evidence).size !== evidence.length) throw new Error('--evidence paths must be unique'); + return { command, track: values.track, level, evidence, out: resolve(values.out), + ...(values.recipe ? { recipe: values.recipe } : {}) }; +} + +function main(): void { + const args = parsePackBudgetArgs(process.argv); + if (!listTracks().includes(args.track)) throw new Error(`unknown track ${args.track}`); + const track = loadTrack(args.track); + if (!isDeclaredLevel(track, args.level)) throw new Error(`L${args.level} is not declared for ${args.track}`); + const binding = resolveRecipeRelease(track, args.level, args.recipe); + if (!binding) throw new Error(`${args.track} L${args.level} has no recipe release`); + const calibration = resolveCalibrationForRelease(binding.release, { trackRoot: track.dir, alias: `L${args.level}` }); + if (!calibration) throw new Error(`${binding.release.id} has no calibration`); + const loaded = loadPackBudgetEvidence(args.evidence); + const result = recommendPackBudgets({ binding, calibration, evidence: loaded }); + if (existsSync(args.out)) throw new Error(`refusing to replace existing budget measurement: ${args.out}`); + const id = `pack-budget-${args.track}-l${args.level}-${new Date().toISOString().replace(/[-:.TZ]/g, '').slice(0, 14)}`; + const artifact = writeArtifact(args.out, { kind: 'pack_budget_measurement', id, + identities: recipeArtifactIdentities(binding.release, { + calibration: { id: calibration.id, sha256: calibration.contentSha256 }, + }), + payload: { schemaVersion: 1, track: args.track, level: args.level, policy: PACK_BUDGET_POLICY, + runner: result.measuredRunner, + evidence: loaded.map(item => { + const stackAdapter = item.artifact.identities.stackAdapter; + if (!stackAdapter) throw new Error(`${item.path} has no stack adapter identity`); + return { path: relative(dirname(args.out), item.path).replaceAll('\\', '/'), + sha256: item.sha256, stack: stackAdapter.id }; + }), + samples: result.samples, recommendations: result.recommendations } }); + console.log(JSON.stringify(artifactPayload(artifact), null, 2)); +} + +if (process.argv[1] && pathToFileURL(resolve(process.argv[1])).href === import.meta.url) { + try { main(); } + catch (error) { + console.error(error instanceof Error ? error.message : String(error)); + process.exitCode = 2; + } +} diff --git a/tools/stack-bench/commands/preflight-cli.ts b/tools/stack-bench/commands/preflight-cli.ts new file mode 100644 index 00000000000..066389d0363 --- /dev/null +++ b/tools/stack-bench/commands/preflight-cli.ts @@ -0,0 +1,89 @@ +import { resolve } from 'node:path'; +import { parseArgs } from 'node:util'; + +import { DEFAULT_BUILD_IMAGE } from '../src/composition/product-config.js'; +import { STACK_BENCH_ROOT } from '../src/package-root.js'; +import { stackBenchResultsRoot } from '../src/runtime/operational-paths.js'; +import type { PreflightReport, PreflightRequest } from '../src/runtime/preflight.js'; + +function splitList(value: unknown): string[] { + return String(value).split(',').map(item => item.trim()).filter(Boolean); +} + +export function parsePreflightArgs( + argv: string[], + { env = process.env }: { env?: NodeJS.ProcessEnv } = {}, +): PreflightRequest { + const { values } = parseArgs({ args: argv.slice(2), options: { + backend: { type: 'string', multiple: true }, + track: { type: 'string' }, + levels: { type: 'string' }, + recipe: { type: 'string' }, + 'run-index': { type: 'string' }, + parallelism: { type: 'string' }, + 'agent-adapter': { type: 'string' }, + 'provider-route': { type: 'string' }, + 'max-output-tokens': { type: 'string' }, + guidance: { type: 'string' }, + pack: { type: 'string', multiple: true }, + check: { type: 'string', multiple: true }, + image: { type: 'string' }, + 'results-dir': { type: 'string' }, + report: { type: 'string' }, + smoke: { type: 'boolean' }, + json: { type: 'boolean' }, + } }); + const request: PreflightRequest = { backends: [], track: 'ecommerce', levels: '1', levelList: [], + runIndex: 0, parallelism: 1, + agentAdapter: 'claude-code', guidance: 'prescribed', packIds: [], checkKeys: [], smoke: false, + image: env.STACK_BENCH_IMAGE ?? DEFAULT_BUILD_IMAGE, + resultsDir: stackBenchResultsRoot(STACK_BENCH_ROOT, env) }; + request.backends = (values.backend ?? []).flatMap(splitList); + if (values.track !== undefined) request.track = values.track; + if (values.levels !== undefined) request.levels = values.levels; + if (values.recipe !== undefined) request.recipe = values.recipe; + if (values['run-index'] !== undefined) request.runIndex = Number(values['run-index']); + if (values.parallelism !== undefined) request.parallelism = Number(values.parallelism); + if (values['agent-adapter'] !== undefined) request.agentAdapter = values['agent-adapter']; + if (values['provider-route'] !== undefined) request.providerRoute = values['provider-route']; + if (values['max-output-tokens'] !== undefined) request.maxOutputTokens = Number(values['max-output-tokens']); + if (values.guidance !== undefined) request.guidance = values.guidance; + request.packIds = (values.pack ?? []).flatMap(splitList); + request.checkKeys = (values.check ?? []).flatMap(splitList); + if (values.image !== undefined) request.image = values.image; + if (values['results-dir'] !== undefined) request.resultsDir = resolve(values['results-dir']); + if (values.report !== undefined) request.report = resolve(values.report); + request.smoke = values.smoke ?? false; + request.json = values.json; + if (!request.backends.length) throw new Error('--backend is required (comma-separated values are accepted)'); + if (request.guidance !== 'neutral' && request.guidance !== 'prescribed') { + throw new Error('--guidance must be neutral or prescribed'); + } + request.backends = [...new Set(request.backends)].sort(); + if (!Number.isInteger(request.runIndex) || request.runIndex < 0) { + throw new Error('--run-index must be a non-negative integer'); + } + if (!Number.isInteger(request.parallelism) || (request.parallelism ?? 0) < 1) { + throw new Error('--parallelism must be a positive integer'); + } + const match = String(request.levels).match(/^(\d+)(?:-(\d+))?$/); + if (!match || Number(match[2] ?? match[1]) < Number(match[1])) { + throw new Error('--levels must be N or N-M'); + } + request.levelList = Array.from({ length: Number(match[2] ?? match[1]) - Number(match[1]) + 1 }, + (_, index) => Number(match[1]) + index); + if (request.recipe && request.levelList.length !== 1) { + throw new Error('--recipe requires exactly one requested level'); + } + return request; +} + +export function printPreflightReport(report: PreflightReport): void { + console.log(`Stack Bench preflight: ${report.ok ? 'READY' : 'NOT READY'}`); + for (const check of report.checks) { + const mark = check.status === 'pass' ? 'PASS' : check.status === 'warn' ? 'WARN' : 'FAIL'; + console.log(` ${mark.padEnd(4)} ${check.id.padEnd(28)} ${check.summary}`); + if (check.remediation && check.status === 'fail') console.log(` hint: ${check.remediation}`); + } + console.log(`\n${report.summary.passed} passed, ${report.summary.failed} failed, ${report.summary.warnings} warnings`); +} diff --git a/tools/stack-bench/commands/preflight.ts b/tools/stack-bench/commands/preflight.ts new file mode 100644 index 00000000000..45cb7a40af1 --- /dev/null +++ b/tools/stack-bench/commands/preflight.ts @@ -0,0 +1,19 @@ +#!/usr/bin/env node + +import { parsePreflightArgs, printPreflightReport } from './preflight-cli.js'; +import { runPreflight, writePreflightReport } from '../src/runtime/preflight.js'; + +let request; +try { + request = parsePreflightArgs(process.argv); +} catch (error) { + console.error(`preflight: ${error instanceof Error ? error.message : String(error)}`); + console.error('Usage: stack-bench preflight --backend spacetime[,postgres,mongodb] [--track ecommerce] [--levels 1-2] [--smoke]'); + process.exit(2); +} + +const report = runPreflight(request); +if (request.report) writePreflightReport(request.report, report); +if (request.json) console.log(JSON.stringify(report, null, 2)); +else printPreflightReport(report); +process.exitCode = report.ok ? 0 : 1; diff --git a/tools/stack-bench/commands/progression-graph.ts b/tools/stack-bench/commands/progression-graph.ts new file mode 100644 index 00000000000..82dc0a3be9e --- /dev/null +++ b/tools/stack-bench/commands/progression-graph.ts @@ -0,0 +1,21 @@ +import { dirname, join, resolve } from 'node:path'; + +import { STACK_BENCH_ROOT } from '../src/package-root.js'; +import { writeProgressionGraph } from '../src/progression/progression-graph.js'; + +interface ProgressionGraph { + nodes: unknown[]; + levels: number; +} + +const definitionPath = process.argv[2]; +if (!definitionPath) { + throw new Error('usage: progression-graph [html-path]'); +} +const resolvedDefinitionPath = resolve(definitionPath); +const graph: ProgressionGraph = writeProgressionGraph({ + definitionPath: resolvedDefinitionPath, + htmlPath: process.argv[3] ?? join(STACK_BENCH_ROOT, 'docs', 'dependency-graph.html'), + trackRoot: dirname(dirname(resolvedDefinitionPath)), +}); +console.log(`Rendered ${graph.nodes.length} nodes across ${graph.levels} levels.`); diff --git a/tools/stack-bench/commands/qualification-cli.ts b/tools/stack-bench/commands/qualification-cli.ts new file mode 100644 index 00000000000..97bd1e37909 --- /dev/null +++ b/tools/stack-bench/commands/qualification-cli.ts @@ -0,0 +1,253 @@ +#!/usr/bin/env node + +import { existsSync, readFileSync } from 'node:fs'; +import { basename, dirname, extname, join, resolve } from 'node:path'; +import { pathToFileURL } from 'node:url'; +import { parseArgs as parseNodeArgs } from 'node:util'; + +import { calibrationQualificationIdentity, resolveCalibrationForRelease } from '../src/composition/calibration-compiler.js'; +import { resolveRecipeRelease } from '../src/composition/recipe-release.js'; +import { isDeclaredLevel, listTracks, loadTrack } from '../src/composition/tracks.js'; +import { PACK_BUDGET_POLICY } from '../src/composition/pack-budget.js'; +import { STACK_BENCH_ROOT } from '../src/package-root.js'; +import { stackBenchResultsRoot } from '../src/runtime/operational-paths.js'; +import { companionReferenceArtifactPath, MAX_MUTATION_WORKERS, validateMutationWorkerCount } + from '../src/references/reference-live.js'; +import type { CalibrationPlan } from '../src/composition/calibration-compiler.js'; +import type { RecipeBinding, RecipeRelease } from '../src/composition/recipe-release.js'; + +interface QualificationArgs { + command?: string; + track: string | null; + level: number | null; + recipe?: string; + mutationWorkers?: number; +} + +interface QualificationBlocker { + code: string; + path: string; + summary: string; +} + +export function parseQualificationArgs(argv: string[]): QualificationArgs { + const { positionals, values } = parseNodeArgs({ args: argv.slice(2), allowPositionals: true, + options: { track: { type: 'string' }, level: { type: 'string' }, recipe: { type: 'string' }, + 'mutation-workers': { type: 'string' } } }); + const args: QualificationArgs = { command: positionals[0], track: values.track ?? null, + level: values.level === undefined ? null : Number(values.level), + ...(values.recipe === undefined ? {} : { recipe: values.recipe }), + ...(values['mutation-workers'] === undefined ? {} : { + mutationWorkers: validateMutationWorkerCount(Number(values['mutation-workers'])) }) }; + if (args.command !== 'status' || typeof args.track !== 'string' || !args.track + || positionals.length !== 1 || args.level === null || !Number.isInteger(args.level) || args.level < 1) { + throw new Error('usage: node dist/commands/qualification-cli.js status --track --level ' + + '[--recipe ] [--mutation-workers ]'); + } + return args; +} + +function blocker(code: string, path: string, summary: string): QualificationBlocker { + return { code, path, summary }; +} + +function evidencePlan(calibration: CalibrationPlan) { + const stacks = [...calibration.qualification.stacks].sort(); + const evidence = []; + for (const stack of stacks) { + for (let repetition = 1; repetition <= calibration.qualification.referenceRepetitions; repetition += 1) { + evidence.push({ kind: 'reference', stack, repetition }); + } + for (let repetition = 1; repetition <= calibration.qualification.mutationRepetitions; repetition += 1) { + evidence.push({ kind: 'mutation', stack, repetition }); + } + } + for (let repetition = 1; repetition <= calibration.nullControl.repetitions; repetition += 1) { + evidence.push({ kind: 'null', stack: null, repetition }); + } + return evidence; +} + +export interface CalibrationMutationSelection { + mutations: Array<{ backend: string; path: string; targets: Array<{ id: string }> }>; +} + +export function mutationWorkerCount(calibration: CalibrationMutationSelection, stack: string, + readManifest: (path: string) => { mutations?: { id: string }[] } = path => + JSON.parse(readFileSync(resolve(STACK_BENCH_ROOT, path), 'utf8')) as { mutations?: { id: string }[] }, + requestedWorkers = MAX_MUTATION_WORKERS) { + validateMutationWorkerCount(requestedWorkers); + const entry = calibration.mutations.find(candidate => candidate.backend === stack); + if (!entry) return 1; + const manifest = readManifest(entry.path); + const selectedIds = new Set(entry.targets.map(target => target.id)); + const selectedMutations = (manifest.mutations ?? []).filter(mutation => + selectedIds.delete(mutation.id)); + if (selectedIds.size) { + throw new Error(`${stack} calibration selects missing mutations: ${[...selectedIds].sort().join(', ')}`); + } + return Math.min(requestedWorkers, Math.max(1, selectedMutations.length)); +} + +function mutationWorkerOption(calibration: CalibrationPlan, stack: string, requestedWorkers: number) { + const workers = mutationWorkerCount(calibration, stack, undefined, requestedWorkers); + return workers > 1 ? ` --mutation-workers ${workers}` : ''; +} + +function qualificationRunDirectory(artifactPath: string): string { + return join(dirname(artifactPath), `${basename(artifactPath, extname(artifactPath))}.runs`); +} + +function defectCheckCoverage(release: RecipeRelease, calibration: CalibrationPlan) { + const selected = calibration.qualification.checks + ? new Set(calibration.qualification.checks) : null; + const scored = release.checkCatalog.filter(check => check.points > 0 + && (selected === null || selected.has(check.stableKey))); + const scoredByKey = new Map(scored.map(check => [check.stableKey, check])); + const stacks = [...calibration.qualification.stacks].sort(); + return { + required: 'every scored check has an exact known-defect test on every supported stack', + totalChecks: scored.length, + totalPoints: scored.reduce((total, check) => total + check.points, 0), + stacks: stacks.map(stack => { + const covered = new Set(calibration.mutations + .filter(entry => entry.backend === stack) + .flatMap(entry => entry.targets.flatMap(target => target.stableKeys)) + .filter(key => scoredByKey.has(key))); + const missing = scored.filter(check => !covered.has(check.stableKey)); + return { + stack, + coveredChecks: covered.size, + coveredPoints: [...covered].reduce((total, key) => total + (scoredByKey.get(key)?.points ?? 0), 0), + missingChecks: missing.map(check => check.stableKey), + }; + }), + }; +} + +export function qualificationReadiness(trackName: string, level: number, recipe: string | null = null, + mutationWorkers = MAX_MUTATION_WORKERS) { + validateMutationWorkerCount(mutationWorkers); + if (!listTracks().includes(trackName)) throw new Error(`unknown qualification track ${trackName}`); + const track = loadTrack(trackName); + if (!isDeclaredLevel(track, level)) { + throw new Error(`L${level} is not declared for ${trackName}`); + } + const binding: RecipeBinding | null = resolveRecipeRelease(track, level, recipe); + if (!binding) throw new Error(`${trackName} L${level} has no recipe release`); + const calibration = resolveCalibrationForRelease(binding.release, + { trackRoot: track.dir, alias: `L${level}` }); + if (!calibration) { + throw new Error(`${binding.release.id} has no L${level} calibration`); + } + const identity = calibrationQualificationIdentity(calibration); + const qualificationLevel = Number(calibration.selection.alias.slice(1)); + const launchBlockers = []; + for (const pack of binding.plan.packs) { + if (pack.budget.status !== 'bounded') { + launchBlockers.push(blocker('pack_budget_unbounded', `packs.${pack.id}.budget`, + `${pack.id} needs a measured maxRuntimeMs before qualification`)); + } + } + + const requiredEvidence = evidencePlan(calibration); + const defectChecks = defectCheckCoverage(binding.release, calibration); + const recorded = new Set(calibration.qualification.evidence.map(entry => + `${entry.kind}:${entry.stack ?? ''}:${entry.repetition}`)); + const qualificationBlockers = [...launchBlockers]; + for (const coverage of defectChecks.stacks.filter(item => item.missingChecks.length > 0)) { + qualificationBlockers.push(blocker('defect_check_coverage_incomplete', + `defectChecks.${coverage.stack}`, + `${coverage.coveredChecks}/${defectChecks.totalChecks} scored checks have exact known-defect tests`)); + } + for (const item of requiredEvidence) { + const key = `${item.kind}:${item.stack ?? ''}:${item.repetition}`; + if (!recorded.has(key)) qualificationBlockers.push(blocker('evidence_missing', `evidence.${key}`, + `${key} has no hash-bound qualification artifact`)); + } + for (const stale of (calibration.qualificationStaleness ?? []) as { + kind: string; stack?: string; repetition: number; reason: string; + }[]) { + const key = `${stale.kind}:${stale.stack ?? ''}:${stale.repetition}`; + qualificationBlockers.push(blocker('qualification_evidence_stale', `evidence.${key}`, + `${key} must be regenerated: ${stale.reason}`)); + } + const output = join(stackBenchResultsRoot(STACK_BENCH_ROOT), 'qualification'); + const stacks = [...calibration.qualification.stacks].sort(); + const budgetEvidence = stacks.map(stack => + `${output}/budget-input/${trackName}-l${qualificationLevel}-${stack}.json`); + const budgetPreparationRequired = launchBlockers.some(item => item.code === 'pack_budget_unbounded'); + const recipeOption = ` --recipe ${binding.release.id}`; + const featureCatalog = calibration.qualification.featureCatalog; + const featureCatalogOption = featureCatalog + ? ` --feature-catalog ${featureCatalog.path}` : ''; + const combinedReferenceEvidence = calibration.qualification.referenceRepetitions + === calibration.qualification.mutationRepetitions; + const artifactStem = `${trackName}-l${qualificationLevel}-${binding.release.contentSha256.slice(0, 12)}`; + const artifactPaths = { + references: Object.fromEntries(stacks.map(stack => [stack, + `${output}/${artifactStem}-${stack}-reference.json`])), + mutations: Object.fromEntries(stacks.map(stack => [stack, + `${output}/${artifactStem}-${stack}-mutation.json`])), + null: `${output}/${artifactStem}-null.json`, + }; + const launchPaths = new Set([artifactPaths.null]); + for (const stack of stacks) { + const mutationPath = artifactPaths.mutations[stack]; + const referencePath = artifactPaths.references[stack]; + if (!mutationPath || !referencePath) throw new Error(`qualification path is missing for ${stack}`); + launchPaths.add(mutationPath); + launchPaths.add(qualificationRunDirectory(mutationPath)); + launchPaths.add(combinedReferenceEvidence + ? companionReferenceArtifactPath(mutationPath) : referencePath); + if (!combinedReferenceEvidence) { + launchPaths.add(qualificationRunDirectory(referencePath)); + } + } + for (const path of [...launchPaths].filter(existsSync).sort()) { + launchBlockers.push(blocker('qualification_output_exists', path, + 'qualification output already exists')); + } + return { + qualificationSchemaVersion: 1, + scope: { track: trackName, level, recipe: { id: binding.release.id, + contentSha256: binding.release.contentSha256 }, + calibration: { ...identity, contentSha256: calibration.contentSha256 }, + runner: calibration.qualification.runner ?? null }, + launch: { ok: launchBlockers.length === 0, blockers: launchBlockers }, + budgetPreparation: { + required: budgetPreparationRequired, + policy: PACK_BUDGET_POLICY, + commands: budgetPreparationRequired ? [ + ...stacks.map((stack, index) => + `qualify-reference --timing-only --backend ${stack} --track ${trackName} --level ${qualificationLevel}${recipeOption}${featureCatalogOption} --repetitions ${calibration.qualification.referenceRepetitions} --out ${budgetEvidence[index]}`), + `pack-budget recommend --track ${trackName} --level ${qualificationLevel}${recipeOption} ${budgetEvidence + .map(path => `--evidence ${path}`).join(' ')} --out ${output}/${trackName}-l${qualificationLevel}-pack-budgets.json`, + ] : [], + }, + requiredEvidence, + defectChecks, + artifactPaths, + commands: qualificationBlockers.length === 0 ? [] : [ + ...stacks.flatMap(stack => [ + ...(!combinedReferenceEvidence ? [ + `qualify-reference --backend ${stack} --track ${trackName} --level ${qualificationLevel}${recipeOption}${featureCatalogOption} --repetitions ${calibration.qualification.referenceRepetitions} --out ${artifactPaths.references[stack]}`, + ] : []), + `qualify-reference --backend ${stack} --track ${trackName} --level ${qualificationLevel}${recipeOption}${featureCatalogOption} --repetitions ${calibration.qualification.mutationRepetitions} --mutations --full-mutations${mutationWorkerOption(calibration, stack, mutationWorkers)} --out ${artifactPaths.mutations[stack]}`, + ]), + `qualify-null --track ${trackName} --level ${qualificationLevel}${recipeOption} --out ${artifactPaths.null}`, + ], + qualification: { ready: qualificationBlockers.length === 0, blockers: qualificationBlockers }, + }; +} + +function main() { + const args = parseQualificationArgs(process.argv); + if (!args.track || args.level === null) throw new Error('track and level are required'); + console.log(JSON.stringify(qualificationReadiness(args.track, args.level, args.recipe, args.mutationWorkers), null, 2)); +} + +if (process.argv[1] && pathToFileURL(resolve(process.argv[1])).href === import.meta.url) { + try { main(); } + catch (error: unknown) { console.error(error instanceof Error ? error.message : String(error)); process.exitCode = 2; } +} diff --git a/tools/stack-bench/commands/recovery.ts b/tools/stack-bench/commands/recovery.ts new file mode 100644 index 00000000000..cf622baf806 --- /dev/null +++ b/tools/stack-bench/commands/recovery.ts @@ -0,0 +1,25 @@ +#!/usr/bin/env node + +import { recoverBackendLease, recoverSupervisedRun } from '../src/runtime/recovery.js'; + +const [command, statePath, option, output] = process.argv.slice(2); +const supervisorRequest = command === 'recover' && statePath !== undefined && process.argv.length === 4; +const leaseRequest = command === 'recover-lease' && statePath !== undefined && option === '--out' + && output !== undefined && process.argv.length === 6; +if (!supervisorRequest && !leaseRequest) { + console.error('Usage:\n' + + ' stack-bench recover \n' + + ' stack-bench recover-lease --out '); + process.exit(2); +} + +try { + const result = leaseRequest + ? recoverBackendLease(statePath, output) + : recoverSupervisedRun(statePath); + console.log(JSON.stringify(result, null, 2)); + process.exitCode = result.ok ? 0 : 1; +} catch (error) { + console.error(`recovery: ${error instanceof Error ? error.message : String(error)}`); + process.exitCode = 2; +} diff --git a/tools/stack-bench/commands/repair-cli.ts b/tools/stack-bench/commands/repair-cli.ts new file mode 100644 index 00000000000..b37a06a74a3 --- /dev/null +++ b/tools/stack-bench/commands/repair-cli.ts @@ -0,0 +1,220 @@ +#!/usr/bin/env node + +import { randomUUID } from 'node:crypto'; +import { existsSync, mkdirSync, rmSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { join, resolve } from 'node:path'; +import { pathToFileURL } from 'node:url'; + +import { acquireCampaignLock, releaseCampaignLock } from '../src/campaigns/campaign-lock.js'; +import { ARTIFACT_FILE, emptyArtifactIdentities, readArtifact, writeArtifact } + from '../src/evidence/artifacts.js'; +import { STACK_BENCH_ROOT } from '../src/package-root.js'; +import { rescueSupervisedLease } from '../src/runtime/recovery.js'; +import { runBounded } from '../src/runtime/bounded-process.js'; +import type { BoundedProcessResult, RunBoundedOptions } + from '../src/runtime/bounded-process.js'; +import { createRepairGrant, inspectRepairParent } from '../src/runtime/repair-grant.js'; + +const BENCH = join(STACK_BENCH_ROOT, 'dist', 'commands', 'bench.js'); + +export interface RepairStatusArgs { + command: 'status'; + parent: string; + level: number; +} + +export interface RepairGrantArgs { + command: 'grant'; + parent: string; + level: number; + repairs: number; + maxBudgetUsd?: number; + timeoutMinutes: number; +} + +export type RepairArgs = RepairStatusArgs | RepairGrantArgs; + +export function parseRepairArgs(argv: string[]): RepairArgs { + const [command, parent, ...rest] = argv.slice(2); + if (command === 'status' && parent && rest.length === 2 && rest[0] === '--level') { + const level = Number(rest[1]); + if (!Number.isSafeInteger(level) || level < 1) throw new Error('--level must be a positive integer'); + return { command, parent: resolve(parent), level }; + } + if (command !== 'grant' || !parent) { + throw new Error('usage: repair status --level | repair grant --level --repairs [--max-budget-usd ] [--timeout-minutes ]'); + } + const values: { level?: number; repairs?: number; maxBudgetUsd?: number; + timeoutMinutes: number } = { timeoutMinutes: 120 }; + const seen = new Set(); + for (let index = 0; index < rest.length; index += 2) { + const flag = rest[index]; + if (!flag || !['--level', '--repairs', '--max-budget-usd', '--timeout-minutes'].includes(flag) + || index + 1 >= rest.length || seen.has(flag)) { + throw new Error(`invalid or duplicate repair option ${String(flag)}`); + } + seen.add(flag); + const value = Number(rest[index + 1]); + if (flag === '--level') values.level = value; + else if (flag === '--repairs') values.repairs = value; + else if (flag === '--max-budget-usd') values.maxBudgetUsd = value; + else values.timeoutMinutes = value; + } + const level = values.level; + if (level === undefined || !Number.isSafeInteger(level) || level < 1) { + throw new Error('--level must be a positive integer'); + } + const repairs = values.repairs; + if (repairs === undefined || !Number.isSafeInteger(repairs) || repairs < 1) { + throw new Error('--repairs must be a positive safe integer'); + } + if (values.maxBudgetUsd !== undefined + && (!Number.isFinite(values.maxBudgetUsd) || values.maxBudgetUsd <= 0)) { + throw new Error('--max-budget-usd must be a positive number'); + } + if (!Number.isFinite(values.timeoutMinutes) || values.timeoutMinutes < 10 + || values.timeoutMinutes > 480) { + throw new Error('--timeout-minutes must be from 10 through 480'); + } + return { command, parent: resolve(parent), level, + repairs, timeoutMinutes: values.timeoutMinutes, + ...(values.maxBudgetUsd === undefined ? {} : { maxBudgetUsd: values.maxBudgetUsd }) }; +} + +export function repairStatus(parent: string, level: number): Record { + try { + const inspected = inspectRepairParent(parent, level); + return { eligible: true, parentRunId: inspected.parent.id, level, + score: inspected.level.score, max: inspected.level.max, + used: inspected.cumulativeRepairsBefore, + checkpointSha256: inspected.checkpoint.payload.source.sha256 }; + } catch (error) { + return { eligible: false, level, + reason: error instanceof Error ? error.message : String(error) }; + } +} + +interface RepairExecutionDependencies { + execute?: (command: string, argv: string[], + options: RunBoundedOptions) => Promise; + rescue?: (path: string, output: string) => void; + uuid?: () => string; + env?: NodeJS.ProcessEnv; +} + +interface RepairContinuationPayload { + outcome?: unknown; + continuation?: { + parentRunId?: string; + repairsGranted?: number; + level?: number; + [key: string]: unknown; + }; + [key: string]: unknown; +} + +export async function executeRepairGrant(args: RepairGrantArgs, + { execute = runBounded, rescue = rescueSupervisedLease, uuid = randomUUID, + env = process.env }: RepairExecutionDependencies = {}) { + const resolved = createRepairGrant(args.parent, { level: args.level, repairs: args.repairs }); + const lock = acquireCampaignLock(join(resolved.root, '.repair-control'), { + id: `repair-l${args.level}`, + contentSha256: resolved.checkpoint.payload.source.sha256, + }); + const stamp = new Date().toISOString().replace(/[-:.TZ]/g, '').slice(0, 14); + const executionId = `grant-${stamp}-${uuid().replaceAll('-', '').slice(0, 12)}`; + const output = join(resolved.root, 'continuations', executionId); + const privateRoot = join(tmpdir(), 'stack-bench-repair-supervisors'); + const supervisorState = join(privateRoot, `${executionId}.json`); + try { + mkdirSync(output, { recursive: true }); + mkdirSync(privateRoot, { recursive: true, mode: 0o700 }); + const argv = [BENCH, + '--repair-from', resolved.root, + '--repair-level', String(args.level), + '--repairs', String(args.repairs), + '--out', output, + '--no-media']; + if (args.maxBudgetUsd !== undefined) { + argv.push('--max-budget-usd', String(args.maxBudgetUsd)); + } + const childEnv: NodeJS.ProcessEnv = { + ...env, + STACK_BENCH_SUPERVISOR_STATE: supervisorState, + }; + if (resolved.configuration.buildImage) { + childEnv.STACK_BENCH_IMAGE = resolved.configuration.buildImage; + } + const processResult = await execute(process.execPath, argv, { + cwd: STACK_BENCH_ROOT, + env: childEnv, + stdio: 'inherit', + timeoutMs: args.timeoutMinutes * 60_000, + logs: { stdout: join(output, 'process.stdout.log'), + stderr: join(output, 'process.stderr.log') }, + }); + let cleanupError: unknown = null; + if (!processResult.ok && existsSync(supervisorState)) { + try { rescue(supervisorState, output); } + catch (error) { cleanupError = error; } + } + const streams = processResult.logs ? Object.fromEntries(Object.entries(processResult.logs) + .map(([name, value]) => [name, { ...value, path: `process.${name}.log` }])) : null; + writeArtifact(join(output, ARTIFACT_FILE.process), { + kind: 'repair_process', + id: `${executionId}-process`, + attempt: { id: `${executionId}-process`, parentId: resolved.parent.id }, + identities: emptyArtifactIdentities({ + agentAdapter: resolved.parentArtifact.identities.agentAdapter, + stackAdapter: resolved.parentArtifact.identities.stackAdapter, + }), + payload: { schemaVersion: 2, parentRunId: resolved.parent.id, + level: args.level, repairsGranted: args.repairs, + exitCode: processResult.code ?? null, signal: processResult.signal ?? null, + timedOut: processResult.timedOut, streams }, + }); + if (cleanupError) { + const detail = cleanupError instanceof Error ? cleanupError.message : String(cleanupError); + throw new Error(`repair continuation cleanup failed: ${detail}`); + } + const runPath = join(output, ARTIFACT_FILE.run); + if (!existsSync(runPath)) { + throw new Error(`repair continuation produced no run artifact${processResult.timedOut ? ' before its timeout' : ''}`); + } + const run = readArtifact(runPath, + { expectedKind: 'repair_continuation' }); + if (run.attempt.parentId !== resolved.parent.id + || run.payload.continuation?.parentRunId !== resolved.parent.id + || run.payload.continuation?.repairsGranted !== args.repairs + || run.payload.continuation?.level !== args.level) { + throw new Error('repair continuation result does not match its grant'); + } + return { output, process: processResult, run }; + } finally { + rmSync(supervisorState, { force: true }); + releaseCampaignLock(lock); + } +} + +async function main(): Promise { + const args = parseRepairArgs(process.argv); + if (args.command === 'status') { + const status = repairStatus(args.parent, args.level); + console.log(JSON.stringify(status, null, 2)); + if (status.eligible !== true) process.exitCode = 1; + return; + } + const result = await executeRepairGrant(args); + console.log(JSON.stringify({ output: result.output, id: result.run.id, + outcome: result.run.payload.outcome, + continuation: result.run.payload.continuation }, null, 2)); + if (!result.process.ok) process.exitCode = 1; +} + +if (process.argv[1] && pathToFileURL(resolve(process.argv[1])).href === import.meta.url) { + main().catch((error: unknown) => { + console.error(error instanceof Error ? error.message : String(error)); + process.exitCode = 2; + }); +} diff --git a/tools/stack-bench/commands/report-bugs.ts b/tools/stack-bench/commands/report-bugs.ts new file mode 100644 index 00000000000..f1cb76f007b --- /dev/null +++ b/tools/stack-bench/commands/report-bugs.ts @@ -0,0 +1,396 @@ +#!/usr/bin/env node +import { privateGradingDirectory } from '../src/evidence/repair-evidence.js'; +// Turns grading results into a behavioral BUG_REPORT.md for the fix agent. +// +// Report behavior and typed observations, never implementation advice. A setup +// failure must not be described as a failure of the later criterion. + +import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from 'node:fs'; +import { dirname, join, resolve } from 'node:path'; +import { pathToFileURL } from 'node:url'; +import { parseArgs as parseNodeArgs } from 'node:util'; +import { findingStatus, renderRepairFinding } from '../src/actions/action-findings.js'; +import type { Finding } from '../src/actions/action-findings.js'; +import type { ActionEvidence } from '../src/actions/action-contract.js'; +import type { CheckEvidence } from '../src/evidence/check-evidence.js'; +import { sanitiseConsoleError, sanitiseDiagnostic } from '../src/evidence/diagnostic-sanitizer.js'; +import { ARTIFACT_FILE, readArtifactPayload } from '../src/evidence/artifacts.js'; +import { criterionEvidence, evidenceIsRepairable, validateCheckEvidence } from '../src/evidence/check-evidence.js'; +import { assertAgentVisibleText } from '../src/composition/agent-visible-contract.js'; +import { CODING_CONTAINER_BUG_REPORT_FILE, CODING_CONTAINER_START_SCRIPT } + from '../src/runtime/coding-container-policy.js'; + +interface RepairHistoryEntry { + round?: number; + beforeScore?: number; + beforeMax?: number; + afterScore?: number; + afterMax?: number; + result?: string; + remainingFailures?: string[]; +} + +interface ReportBugsArgs { + app: string; + results: string; + out: string; + archive?: string; + history: RepairHistoryEntry[]; + checks: string[] | null; + controls: string[] | null; + priorRegression: string | null; + regressionContext: boolean; +} + +interface ParsedArgs { + app?: string; + results?: string; + out?: string; + archive?: string; + history?: unknown; + checks?: unknown; + controls?: unknown; +} + +interface Criterion { + id?: string; + stableKey?: string; + desc?: string; + statedBy?: string; + points?: number; + evidence?: unknown; +} + +interface GradeFeature { + name?: string; + consoleErrors?: string[]; + criteria?: Criterion[]; + setupEvidence?: unknown; +} + +interface GradePayload { + features?: GradeFeature[]; +} + +interface ContractResult { + id: string; + status: string; + detail?: string; +} + +interface ContractLintPayload { + results?: ContractResult[]; +} + +interface GradeBundlePayload { + backend?: string; + outcome?: { kind?: string; phase?: string; reason?: string }; +} + +interface RepairBug { + area: string; + actor: string | null; + action: string | null; + expected: string | null; + observed: string; + consoleErrors: string[]; + contract: boolean; + context?: string[]; +} + +// Only completed public interactions, never raw action inputs or diagnostics. +// These observations explain where a sequence stopped without teaching a fix. +function observationContext(evidence: CheckEvidence): string[] { + const actions = evidence.actions.map(entry => ({ actor: entry.actor, + evidence: entry.evidence as ActionEvidence })); + const failureIndex = actions.findLastIndex(entry => entry.evidence.status === 'failed'); + const context: string[] = evidence.phase === 'setup' + ? ['Setup stopped before the named behavior was reached.'] : []; + if (failureIndex < 0) return context; + const completed: string[] = []; + const lifecycle: string[] = []; + for (const { actor, evidence: action } of actions.slice(0, failureIndex)) { + if (action.status !== 'passed') continue; + const observation = action.observation && typeof action.observation === 'object' + ? action.observation as Record : {}; + if (action.action.id === 'click' && typeof observation.clicked === 'string') { + completed.push(`${actor ? `${sanitiseDiagnostic(actor, 120)}: ` : ''}${sanitiseDiagnostic(observation.clicked, 120)}`); + } + if (action.action.id === 'callAction' && typeof observation.action === 'string' + && Number.isInteger(observation.status) && Number(observation.status) >= 100 && Number(observation.status) <= 599) { + completed.push(`${actor ? `${sanitiseDiagnostic(actor, 120)}: ` : ''}${sanitiseDiagnostic(observation.action, 120)} returned HTTP ${observation.status}`); + } + const account = ({ signIn: 'sign-in completed', signUp: 'account creation completed', + freshClient: 'fresh client opened' } as Record)[action.action.id]; + if (account) completed.push(`${actor ? `${sanitiseDiagnostic(actor, 120)}: ` : ''}${account}`); + const operations: Record = { reload: 'page reloaded', stopAppServer: 'application server stopped', + startAppServer: 'application server started', restartBackend: 'database runtime restarted' }; + const operation = operations[action.action.id]; + if (operation) lifecycle.push(operation); + } + if (completed.length) context.push(`Recent completed actions: ${completed.slice(-8).join(' → ')}.`); + if (lifecycle.length) context.push(`Completed lifecycle actions: ${[...new Set(lifecycle)].join('; ')}.`); + if (evidence.finding && ['control-missing', 'control-not-ready', 'control-blocked', 'control-unreadable', + 'choice-missing', 'page-timeout'].includes(evidence.finding.kind)) { + context.push('The sequence stopped at this control; later behavior was not observed.'); + } + if (evidence.finding?.kind === 'page-error') { + context.push('The sequence stopped at this action; later behavior was not observed.'); + } + if (evidence.finding && ['value-mismatch', 'number-mismatch'].includes(evidence.finding.kind)) { + context.push('The sequence stopped at this value check; later behavior was not observed.'); + } + return context; +} + +// The public verb for the step that failed. Control and action names are the +// agent's own vocabulary; nothing else about the step is repeated. +function failedAction(action: string | undefined, finding: Finding | null): string | null { + if (action === 'fill') { + return finding?.kind === 'choice-missing' ? 'Select the requested choice' : 'Enter the requested value'; + } + if (action === 'click') return 'Use the requested control'; + if (action === 'signIn') return 'Sign in'; + if (action === 'signUp') return 'Create the account'; + if (action === 'reload') return 'Reload the page'; + return null; +} + +// What the application did, from the finding alone. A failure without a +// finding (the feature's setup failed before this behavior was reached) +// says so and nothing more. +function observed(finding: Finding | null, phase: string): string { + if (finding?.kind === 'page-error') { + // Raw browser diagnostics can contain URLs, credentials and private probe text. + // Report only a recognized transport code, never the surrounding diagnostic. + const code = finding.fields.detail?.match(/\b(?:net::)?(ERR_CONNECTION_REFUSED|ERR_CONNECTION_RESET|ERR_CONNECTION_CLOSED|ERR_CONNECTION_TIMED_OUT|ERR_NAME_NOT_RESOLVED|ERR_ADDRESS_UNREACHABLE|ERR_EMPTY_RESPONSE|ERR_TIMED_OUT)\b/)?.[1]; + if (code) return `the browser request failed (${code})`; + } + if (finding) return renderRepairFinding(finding); + return phase === 'setup' + ? 'the application did not reach this behavior; an earlier step of the same feature failed' + : 'a failure was recorded without a detailed observation'; +} + +export function parseReportBugsArgs(argv: string[]): ReportBugsArgs { + const { values } = parseNodeArgs({ args: argv.slice(2), options: { + app: { type: 'string' }, results: { type: 'string' }, out: { type: 'string' }, + archive: { type: 'string' }, + 'history-json': { type: 'string' }, 'checks-json': { type: 'string' }, + 'controls-json': { type: 'string' }, + 'prior-regression': { type: 'string' }, + 'regression-context': { type: 'boolean' }, + } }); + const args: ParsedArgs = { app: values.app, results: values.results, out: values.out, + archive: values.archive, + history: values['history-json'] === undefined ? undefined : JSON.parse(values['history-json']), + checks: values['checks-json'] === undefined ? undefined : JSON.parse(values['checks-json']), + controls: values['controls-json'] === undefined ? undefined : JSON.parse(values['controls-json']) }; + if (!args.app) { + throw new Error('Usage: report-bugs --app [--out ]'); + } + args.results ??= privateGradingDirectory(args.app); + args.out ??= join(args.app, CODING_CONTAINER_BUG_REPORT_FILE); + args.history ??= []; + if (!Array.isArray(args.history)) throw new Error('--history-json must contain an array'); + args.checks ??= null; + if (args.checks !== null && (!Array.isArray(args.checks) + || args.checks.some(check => typeof check !== 'string' || !check) + || new Set(args.checks).size !== args.checks.length)) { + throw new Error('--checks-json must contain distinct non-empty strings'); + } + args.controls ??= null; + if (args.controls !== null && (!Array.isArray(args.controls) + || args.controls.some(control => typeof control !== 'string' || !control) + || new Set(args.controls).size !== args.controls.length)) { + throw new Error('--controls-json must contain distinct non-empty strings'); + } + return { app: args.app, results: args.results, out: args.out, archive: args.archive, + history: args.history as RepairHistoryEntry[], checks: args.checks as string[] | null, + controls: args.controls as string[] | null, + priorRegression: values['prior-regression'] ?? null, + regressionContext: values['regression-context'] ?? false }; +} + +function priorRegressionSection(path: string): string[] { + const details = assertAgentVisibleText(readFileSync(resolve(path), 'utf8')).trim() + .replace(/^### /gm, '#### ') + .replace(/^## /gm, '### '); + if (!details) throw new Error('prior regression report has no failure details'); + return [ + '## Previous repair regression', + '', + 'The previous repair was rolled back because it broke behavior that already worked.', + 'Keep this behavior working while you fix the current problems.', + '', + ...details.split(/\r?\n/), + '', + ]; +} + +export function createBugReport(args: ReportBugsArgs): number { + const resultsDir = resolve(args.results); + if (!existsSync(resultsDir)) throw new Error(`No grading results in ${resultsDir}`); + + const bugs: RepairBug[] = []; + const reportedSetups = new Set(); + const selectedChecks = args.checks === null ? null : new Set(args.checks); + const selectedControls = args.controls === null ? null : new Set(args.controls); + + for (const file of readdirSync(resultsDir).filter(name => /^grading-.*\.json$/.test(name))) { + const report = readArtifactPayload(join(resultsDir, file), { expectedKind: 'grade' }); + for (const feature of report.features ?? []) { + // Repairs receive only scored, typed application failures. + for (const criterion of feature.criteria ?? []) { + if (selectedChecks && (!criterion.stableKey + || !selectedChecks.has(criterion.stableKey))) continue; + if (!(Number(criterion.points) > 0)) continue; + const evidence = criterionEvidence(criterion); + if (!evidenceIsRepairable(evidence)) continue; + const failure = evidence.phase === 'setup' && feature.setupEvidence + ? validateCheckEvidence(feature.setupEvidence) : evidence; + if (!evidenceIsRepairable(failure) + || (failure.finding && findingStatus(failure.finding) !== 'failed')) continue; + if (evidence.phase === 'setup') { + // One failed setup is copied to each selected criterion it prevented. + // Use full evidence, not rendered prose, so distinct failures stay separate. + const key = JSON.stringify({ area: feature.name, failure }); + if (reportedSetups.has(key)) continue; + reportedSetups.add(key); + } + const actionEntry = failure.actions.findLast(entry => + entry.evidence !== null && typeof entry.evidence === 'object' + && (entry.evidence as { status?: string }).status === 'failed') ?? failure.actions.at(-1); + const actionId = actionEntry && typeof actionEntry.evidence === 'object' && actionEntry.evidence + ? String((actionEntry.evidence as { action?: { id?: string } }).action?.id ?? '') : undefined; + const expected = evidence.phase === 'setup' ? null + : (criterion.desc ?? criterion.statedBy ?? '').trim() || 'the requested behavior'; + bugs.push({ + area: sanitiseDiagnostic(feature.name, 120), + actor: sanitiseDiagnostic(actionEntry?.actor ?? failure.actor, 120) || null, + action: failedAction(actionId, failure.finding), + expected, + observed: observed(failure.finding, evidence.phase), + context: observationContext(failure), + consoleErrors: [...new Set((feature.consoleErrors ?? []) + .map(sanitiseConsoleError).filter(Boolean))].slice(0, 3), + contract: false, + }); + } + } + } + + // Contract failures are separate because the interface name is itself the public + // requirement here. Behavioral failures above must never expose one. + const lintPath = join(resultsDir, ARTIFACT_FILE.contractLint); + if (existsSync(lintPath)) { + const lint = readArtifactPayload(lintPath, { expectedKind: 'contract_lint' }); + for (const result of (lint.results ?? []).filter(item => item.status === 'FAIL' + && (!selectedControls || selectedControls.has(item.id)))) { + bugs.push({ + area: 'Application interface', + actor: null, + action: null, + expected: `A visible element for "${(result.detail ?? '').split('expected: ').pop()}" must use the "${result.id}" application interface`, + observed: sanitiseDiagnostic(result.detail + ?? `no visible element with id="${result.id}" was found after a clean reset`, 500), + consoleErrors: [], contract: true, + }); + } + } + + const bundlePath = join(resultsDir, ARTIFACT_FILE.gradeBundle); + if (existsSync(bundlePath)) { + const bundle = readArtifactPayload(bundlePath, { expectedKind: 'grade_bundle' }); + if (bundle.outcome?.kind === 'app_failure' && bundle.outcome.reason) { + const expectedByPhase: Record = { + 'database-provenance': `The app must use the ${bundle.backend} database and connection supplied for this run.`, + 'application-layout': 'The app must use a project layout that can be built, started, and reset repeatedly.', + 'application-restart': `The app must provide ${CODING_CONTAINER_START_SCRIPT}. From clean source, it must install dependencies, build, and start the complete application without changing source files.`, + }; + const expected = expectedByPhase[bundle.outcome.phase ?? ''] + ?? 'The app must start successfully in the supplied environment.'; + bugs.unshift({ + area: 'Application setup', + actor: null, + action: null, + expected, + observed: sanitiseDiagnostic(bundle.outcome.reason, 500), + consoleErrors: [], + contract: false, + }); + } + } + + if (bugs.length === 0) { + console.log('No failures — no bug report written.'); + return 3; + } + + const behavioral = bugs.filter(bug => !bug.contract); + const contractFailures = bugs.filter(bug => bug.contract); + const lines = args.regressionContext ? [] : [ + '# Bug Report', + '', + 'The application has these problems after a clean database reset and a fresh', + 'restart. Fix the behavior, then redeploy.', + 'Do not change behavior that is already correct. A result from existing local', + 'state does not replace the clean result below.', + '', + ]; + + if (!args.regressionContext && args.history.length) { + lines.push('## Earlier work', ''); + lines.push('Use the current source as the starting point. Preserve earlier fixes while', + 'addressing the remaining problems below.', ''); + } + + if (behavioral.length) { + lines.push('## Behavior', ''); + behavioral.forEach((bug, index) => { + lines.push(`### Bug ${index + 1}: ${bug.area}`, ''); + if (bug.actor) lines.push(`**Actor/session:** ${bug.actor}`, ''); + if (bug.action) lines.push(`**Failed action:** ${bug.action}`, ''); + if (bug.expected) lines.push(`**Expected:** ${bug.expected}`, ''); + lines.push(`**Actual:** ${bug.observed}`, ''); + if (bug.context?.length) lines.push(`**Observed context:** ${bug.context.join(' ')}`, ''); + if (bug.consoleErrors.length) { + lines.push('**Console or network errors:**', ''); + bug.consoleErrors.forEach(error => lines.push(`- \`${error}\``)); + lines.push(''); + } + }); + } + + if (contractFailures.length) { + lines.push('## Application interface', ''); + lines.push('These required elements were not available in the clean application state:', ''); + contractFailures.forEach(bug => { + lines.push(`- **Expected:** ${bug.expected}`); + lines.push(` **Actual:** ${bug.observed}`); + }); + lines.push(''); + } + + if (args.priorRegression) lines.push(...priorRegressionSection(args.priorRegression)); + + const reportText = assertAgentVisibleText(lines.join('\n')); + writeFileSync(args.out, reportText); + if (args.archive) { + mkdirSync(dirname(args.archive), { recursive: true }); + writeFileSync(args.archive, reportText); + } + console.log(`Wrote ${bugs.length} bug(s) to ${args.out}`); + return 0; +} + +function main(): void { + try { + process.exitCode = createBugReport(parseReportBugsArgs(process.argv)); + } catch (error) { + console.error(error instanceof Error ? error.message : String(error)); + process.exitCode = 2; + } +} + +if (process.argv[1] && pathToFileURL(resolve(process.argv[1])).href === import.meta.url) main(); diff --git a/tools/stack-bench/commands/reset-backend.ts b/tools/stack-bench/commands/reset-backend.ts new file mode 100644 index 00000000000..1e08c6da017 --- /dev/null +++ b/tools/stack-bench/commands/reset-backend.ts @@ -0,0 +1,24 @@ +#!/usr/bin/env node + +import { GENERATED_APP_LAYOUT_EXIT_CODE, resetBackend } from '../src/stacks/backend-reset.js'; +import { GeneratedAppLayoutError } from '../src/runtime/spacetime-layout.js'; +import { redactCredentials } from '../src/evidence/diagnostic-sanitizer.js'; + +const [backend, app] = process.argv.slice(2); +if (!backend || !app) throw new Error('usage: node dist/commands/reset-backend.js '); + +Promise.resolve().then(() => resetBackend({ backend, app })).then(result => { + console.log(result); +}).catch(error => { + if (error instanceof GeneratedAppLayoutError || error?.code === 'generated_app_layout') { + console.error(`GENERATED_APP_LAYOUT: ${error.message}`); + process.exitCode = GENERATED_APP_LAYOUT_EXIT_CODE; + return; + } + const childOutput = [error?.stderr, error?.stdout] + .filter(value => value !== undefined && value !== null && String(value).trim()) + .map(value => String(value).trim()).join('\n'); + if (childOutput) console.error(redactCredentials(childOutput).slice(-2000)); + console.error(redactCredentials(error.stack ?? error.message)); + process.exitCode = 1; +}); diff --git a/tools/stack-bench/commands/run-suite.ts b/tools/stack-bench/commands/run-suite.ts new file mode 100644 index 00000000000..a2afc2369ef --- /dev/null +++ b/tools/stack-bench/commands/run-suite.ts @@ -0,0 +1,1222 @@ +#!/usr/bin/env node +import { privateGradingDirectory } from '../src/evidence/repair-evidence.js'; + +import { execFile, execFileSync } from 'node:child_process'; +import type { ExecFileException, ExecFileSyncOptionsWithStringEncoding } from 'node:child_process'; +import { randomUUID } from 'node:crypto'; +import { performance } from 'node:perf_hooks'; +import { measurePhase, type PhaseTiming } from '../src/evidence/phase-timing.js'; +import { readFileSync, writeFileSync, mkdirSync, existsSync, readdirSync, rmSync } from 'node:fs'; +import { join, resolve } from 'node:path'; +import { pathToFileURL } from 'node:url'; +import { setTimeout as sleep } from 'node:timers/promises'; +import { parseArgs as parseNodeArgs, promisify } from 'node:util'; +import { chromium } from 'playwright'; +import { attemptBrowserLaunchOptions } from '../container/browser-pipe.js'; +import type { Browser, BrowserServer } from 'playwright'; +import { Actor } from '../grader/grade.js'; +import { ACTION_REGISTRY } from '../src/actions/action-catalog.js'; +import { ActionApplicationFailure, executeAction } from '../src/actions/action-contract.js'; +import { runApplicationNavigation } from '../src/actions/browser-navigation.js'; +import { stableElementSelector } from '../src/actions/element-selector.js'; +import { dbName, loadTrack, suitesFor, DEFAULT_TRACK } from '../src/composition/tracks.js'; +import { controlAppServer, parseRuntimeControlSpec } + from '../src/runtime/backend-control.js'; +import type { RuntimeControlSpec } from '../src/runtime/backend-control.js'; +import { ARTIFACT_FILE, readArtifactPayload, recipeArtifactIdentities, writeArtifact } + from '../src/evidence/artifacts.js'; +import { bundleRecipeRelease, resolveRecipeRelease } from '../src/composition/recipe-release.js'; +import { createBoundRecipeTaskRequest, resolveBoundRecipeTaskRequest } from '../src/composition/recipe-selection.js'; +import { contractInterfaceNames } from '../src/composition/agent-visible-contract.js'; +import { resolveCalibrationForRelease } from '../src/composition/calibration-compiler.js'; +import { criterionEvidence, evidencePassed } from '../src/evidence/check-evidence.js'; +import { renderEvidenceConsoleLine } from '../src/evidence/evidence-presentation.js'; +import { STACK_ADAPTER_REGISTRY } from '../src/stacks/stack-adapters.js'; +import { requireLeasedDatabase, requireLeasedSpacetime } from '../src/stacks/backend-reset-guard.js'; +import { aggregatePackRuntime, exceededPackBudgets } from '../src/composition/pack-runtime.js'; +import { hashAppSource } from '../src/runtime/source-snapshot.js'; +import { GENERATED_APP_LAYOUT_EXIT_CODE } from '../src/stacks/backend-reset.js'; +import { readBackendLease } from '../src/runtime/backend-lease.js'; +import { redactCredentials } from '../src/evidence/diagnostic-sanitizer.js'; +import { canonicalDefinitionJson } from '../src/composition/definition-plan.js'; +import { sha256 } from '../src/evidence/provenance.js'; +import { GRADER_SOURCE_TIMEOUT_MS } from '../src/runtime/grading-timeout.js'; +import type { BackendLease, BackendLeaseExpectation } from '../src/runtime/backend-lease.js'; +import type { CheckEvidence } from '../src/evidence/check-evidence.js'; +import type { AggregatedPackRuntimeEvidence, PackRuntimeEvidence } from '../src/composition/pack-runtime.js'; +import { isModularRecipeTaskRequest } from '../src/composition/recipe-selection.js'; +import type { BoundRecipeTaskRequestResult, RecipeSelection } from '../src/composition/recipe-selection.js'; +import type { RecipeBinding, RecipeCheck } from '../src/composition/recipe-release.js'; +import type { Track, TrackSuite } from '../src/composition/tracks.js'; + +import { STACK_BENCH_ROOT as ROOT, compiledEntrypoint } from '../src/package-root.js'; +const RESET = compiledEntrypoint('commands', 'reset-backend.js'); + +type Observation = 'scored' | 'observed'; +type Selection = { + schemaVersion: number; + recipe: { id: string; contentSha256: string }; + requested: RecipeSelection['requested']; + sha256: string; + checks: RecipeCheck[]; + scoredPoints: number; + observedChecks?: Array; + observedPoints?: number; + evaluationSha256?: string; + regressionChecks?: Array; + regressionPoints?: number; + observation?: Observation; +}; +type DeclaredSuite = TrackSuite; +type Failure = Error & { stdout?: string; stderr?: string; status?: number | null; signal?: string | null; + code?: string }; +type FailureDetail = { message?: unknown; stderr?: unknown } | null; +type RecipeTaskArgument = { recipe: { id: string; contentSha256?: string } } & Record; +type RunArguments = { + app: string; + url: string; + backend: string; + label: string; + out: string; + level: string; + reset: boolean; + media: boolean; + runIndex: number; + track: string; + packIds: string[]; + checkKeys: string[]; + observation: Observation; + recipe?: string; + recipeTask?: RecipeTaskArgument; + credentialAliases?: unknown; + regressionChecks: string[]; + sourceSha256?: string; + restartSpec?: RuntimeControlSpec; + applicationFailure?: ApplicationFailure; + parentAttemptId?: string; + databaseLease?: BackendLease | null; + browserWsEndpoint?: string; + selection?: Selection | null; + bundleArtifactId: string; +}; +type GradeCriterion = { id: string; stableKey?: string; serverCheck?: string; evidence?: CheckEvidence }; +type GradeFeature = { name: string; criteria: GradeCriterion[]; + cleanupEvidence?: { failures: Array<{ stage: string }> } }; +type GradePayload = { total: number; max: number; features: GradeFeature[]; + selection?: { checks?: RecipeCheck[] }; packRuntime?: PackRuntimeEvidence }; +type LintPayload = { + pass: boolean; + counts: { pass: number; fail: number; blocked: number; scenario: number }; +}; +type ActionsPayload = { missing: string[]; results: unknown[] }; +type RuntimeProvenance = { ok: boolean | null; verified: boolean; reason: string }; +type ApplicationProbeResult = { ok: boolean; detail: string | null }; +type ResetOutcome = { kind: string; phase: string; appFailures?: string[] }; +type ApplicationFailure = ResetOutcome & { kind: 'app_failure'; reason: string }; +type DatabaseProvenance = { ok: boolean; reason: string; url?: string }; +type GradeLeaseReader = typeof readBackendLease; +type MutationDirectoryEntry = { name: string; isDirectory(): boolean; isFile(): boolean }; +type MutationDirectoryReader = (path: string, options: { withFileTypes: true }) => readonly MutationDirectoryEntry[]; +type ProbeResponse = { ok: boolean; status: number }; +type ApplicationFetch = (url: string, init: { signal: AbortSignal }) => Promise; +type DatabaseProvenanceDefinition = Track['databaseProvenance']; +type DatabaseNameLease = { resources: { database?: string | null } }; +type ProvenanceWrite = { ok: true; marker: string } | { ok: false; marker: null; reason: string }; +type ApplicationFailureSelection = { checks: Array<{ executionId: string; points?: number }> }; +type ContractLintArguments = Pick; +type BundleSelection = Selection & { attemptedChecks: string[]; reportedChecks: string[]; + notRun: Array<{ stableKey: string; reason: string }> }; +type Bundle = { + definitionSchemaVersion: number; + recipeRelease: ReturnType; + calibration: { id: string; contentSha256: string } | null; + label: string; track: string; backend: string; url: string; app: string; level: number; + observation: Observation; source?: { sha256: string }; + suites: Record; + totals: Record; + selection: BundleSelection | null; + code?: ReturnType; + error?: string; + outcome?: { kind: string; phase: string; reason?: string; appFailures?: string[] }; + provenance?: DatabaseProvenance & { runtime?: RuntimeProvenance }; + actions?: ActionsPayload | null; + packRuntime?: AggregatedPackRuntimeEvidence; + phaseTimings: PhaseTiming[]; +}; + +const isRecord = (value: unknown): value is Record => + value !== null && typeof value === 'object' && !Array.isArray(value); + +const parseObservation = (value: string): Observation => { + if (value === 'scored' || value === 'observed') return value; + throw new Error('--observation must be scored or observed'); +}; + +export function suitesForRecipe(track: Track, binding: RecipeBinding): DeclaredSuite[] { + if (!binding?.execution?.length) throw new Error('recipe has no typed execution plan'); + return binding.execution.map(entry => ({ + id: entry.id, + spec: resolve(track.dir, entry.source ?? ''), + ...(entry.ownership.kind === 'inherited' + ? { inherited: true, fromLevel: entry.ownership.fromLevel } + : {}), + })); +} + +export function childFailureDetail(failure: FailureDetail = null, stdout = '', limit = 600): string { + const processOutput = [failure?.stderr, stdout] + .filter(value => value !== undefined && value !== null && String(value).trim()) + .join('\n').trim(); + const diagnostic = processOutput || String(failure?.message ?? '').trim(); + const lines = diagnostic.split(/\r?\n/).map(line => line.trim()).filter(Boolean); + if (!lines.length) return ''; + const punctuationOnly = (line: string) => + [...line].every(character => '[]{},'.includes(character)); + const noise = (line: string) => line.startsWith('at ') || /^Node\.js v/.test(line) + || /^node:internal\//.test(line) || /^\^+$/.test(line) || punctuationOnly(line); + const cause = lines.find(line => !noise(line) && /(?:error|failed|timeout|closed|econn|killed)/i.test(line)) + ?? lines.find(line => !noise(line)) ?? lines[0]; + const selected = [cause, ...lines.slice(-4)].filter((line, index, all) => all.indexOf(line) === index); + return selected.join(' | ').slice(0, limit); +} + +export function resetFailureOutcome(error: unknown): ResetOutcome { + const failure = isRecord(error) ? error : {}; + return failure.status === GENERATED_APP_LAYOUT_EXIT_CODE + ? { kind: 'app_failure', phase: 'application-layout', + appFailures: ['application-layout'] } + : failure.code === 'generated_app_not_restartable' + ? { kind: 'app_failure', phase: 'application-restart', + appFailures: ['application-restart'] } + : { kind: 'harness_failure', phase: 'database-reset' }; +} + +export function applicationFailureTotals(selection: ApplicationFailureSelection | null | undefined, + declaredSuites: Array>): Record { + if (!selection?.checks?.length) return {}; + const inherited = new Set(declaredSuites.filter(suite => suite.inherited).map(suite => suite.id)); + const currentMax = selection.checks.filter(check => !inherited.has(check.executionId)) + .reduce((total, check) => total + Number(check.points ?? 0), 0); + const regressionMax = selection.checks.filter(check => inherited.has(check.executionId)) + .reduce((total, check) => total + Number(check.points ?? 0), 0); + return { score: 0, max: currentMax, dirty: false, contractPass: null, + regression: regressionMax ? { score: 0, max: regressionMax } : null }; +} + +export function clearPreviousGradeOutputs(output: string): void { + const generated = existsSync(output) ? readdirSync(output).filter(name => + /^grading-.+\.json$/.test(name) || /^grader-.+\.(?:stdout|stderr)\.log$/.test(name)) : []; + for (const name of [ARTIFACT_FILE.gradeBundle, ARTIFACT_FILE.contractLint, + ARTIFACT_FILE.actions, 'media', 'failure-media', + 'database-provenance', 'application-start.log', ...generated]) { + rmSync(join(output, name), { recursive: true, force: true }); + } +} + +function recordGraderChildResult(output: string, suiteId: string, + result: { stdout?: unknown; stderr?: unknown; failure?: Error | null }) { + const stdout = redactCredentials(String(result.stdout ?? '')); + const stderr = redactCredentials(String(result.stderr ?? '')); + const safeId = String(suiteId).replace(/[^A-Za-z0-9._-]/g, '_'); + const stdoutName = `grader-${safeId}.stdout.log`; + const stderrName = `grader-${safeId}.stderr.log`; + writeFileSync(join(output, stdoutName), stdout); + writeFileSync(join(output, stderrName), stderr); + const failure = result.failure ?? null; + if (failure) Object.assign(failure, { stdout, stderr }); + return { stdout, stderr, failure, stdoutName, stderrName }; +} + +const execFileAsync = promisify(execFile); + +export async function runGraderChild(argv: string[], output: string, suiteId: string) { + try { + const result = await execFileAsync(process.execPath, argv, { encoding: 'utf8', cwd: ROOT, + timeout: COMMAND_TIMEOUT_MS, maxBuffer: 64 * 1024 * 1024 }); + return recordGraderChildResult(output, suiteId, result); + } catch (error) { + const failure = error instanceof Error ? error : new Error(String(error)); + const processFailure = error as ExecFileException & { stdout?: unknown; stderr?: unknown }; + return recordGraderChildResult(output, suiteId, { + stdout: processFailure.stdout, stderr: processFailure.stderr, failure, + }); + } +} + +function gradeLeaseInput(backend: string, env: NodeJS.ProcessEnv): { path: string; + expected: BackendLeaseExpectation } | null { + if (!['mongodb', 'postgres', 'spacetime'].includes(backend)) return null; + const path = String(env.STACK_BENCH_LEASE ?? '').trim(); + const token = String(env.STACK_BENCH_LEASE_TOKEN ?? '').trim(); + if (!path && !token) return null; + if (!path || !token) throw new Error('database grading requires both lease path and lease token'); + return { path, expected: { token, backend, active: true } }; +} + +export function databaseLeaseForGrading(backend: string, env = process.env, { + readLease = readBackendLease, +}: { readLease?: GradeLeaseReader } = {}) { + const input = gradeLeaseInput(backend, env); + if (!input) return null; + const lease = readLease(input.path, input.expected); + if (backend === 'spacetime') { + if (!lease.resources.module || !lease.resources.serverUri) { + throw new Error('active spacetime lease has no complete module target'); + } + return lease; + } + const container = String(lease.resources?.container?.name ?? '').trim(); + const containerId = String(lease.resources?.container?.id ?? '').trim(); + if (!container || !containerId) { + throw new Error(`active ${backend} lease has no complete database container identity`); + } + return lease; +} + +export function databaseNameForGrading(track: Pick, runIndex: number, + lease: DatabaseNameLease | null = null): string { + if (!lease) return dbName(track, runIndex); + const database = String(lease.resources?.database ?? '').trim(); + if (!database) throw new Error('active database lease has no database name'); + return database; +} + +function parseArgs(argv: string[]): RunArguments { + const { values } = parseNodeArgs({ args: argv.slice(2), options: { + app: { type: 'string' }, url: { type: 'string' }, backend: { type: 'string' }, + label: { type: 'string' }, out: { type: 'string' }, level: { type: 'string' }, + recipe: { type: 'string' }, 'recipe-task-json': { type: 'string' }, + 'credential-aliases-json': { type: 'string' }, 'regression-checks-json': { type: 'string' }, + observation: { type: 'string' }, 'source-sha256': { type: 'string' }, + 'no-media': { type: 'boolean' }, track: { type: 'string' }, + pack: { type: 'string', multiple: true }, check: { type: 'string', multiple: true }, + 'restart-spec': { type: 'string' }, 'application-failure-json': { type: 'string' }, + 'run-index': { type: 'string' }, 'no-reset': { type: 'boolean' }, + 'parent-attempt-id': { type: 'string' }, + } }); + const a: RunArguments = { app: values.app ?? '', url: values.url ?? '', + backend: values.backend ?? '', label: values.label ?? '', out: values.out ?? '', + level: values.level ?? '1', reset: !(values['no-reset'] ?? false), + media: !(values['no-media'] ?? false), runIndex: Number(values['run-index'] ?? 0), + track: values.track ?? DEFAULT_TRACK, + packIds: (values.pack ?? []).flatMap(value => value.split(',').filter(Boolean)), + checkKeys: (values.check ?? []).flatMap(value => value.split(',').filter(Boolean)), + observation: parseObservation(values.observation ?? 'scored'), + recipe: values.recipe, + recipeTask: values['recipe-task-json'] === undefined ? undefined : JSON.parse(values['recipe-task-json']), + credentialAliases: values['credential-aliases-json'] === undefined + ? undefined : JSON.parse(values['credential-aliases-json']), + regressionChecks: values['regression-checks-json'] === undefined + ? [] : JSON.parse(values['regression-checks-json']), + sourceSha256: values['source-sha256'], + restartSpec: values['restart-spec'] === undefined + ? undefined : parseRuntimeControlSpec(JSON.parse(values['restart-spec'])), + applicationFailure: values['application-failure-json'] === undefined + ? undefined : JSON.parse(values['application-failure-json']), + parentAttemptId: values['parent-attempt-id'], bundleArtifactId: '' }; + if (!a.app || !a.url || !a.backend || !a.label) { + console.error('Usage: node dist/commands/run-suite.js --app --url --backend --label [--out ] [--media] [--no-reset]'); + process.exit(2); + } + if (!['scored', 'observed'].includes(a.observation)) { + throw new Error('--observation must be scored or observed'); + } + if (a.observation === 'observed' && !/^[a-f0-9]{64}$/.test(a.sourceSha256 ?? '')) { + throw new Error('observed specifications require --source-sha256'); + } + if (a.sourceSha256 !== undefined && !/^[a-f0-9]{64}$/.test(a.sourceSha256)) { + throw new Error('--source-sha256 must be a SHA-256 digest'); + } + if (a.applicationFailure && (a.applicationFailure.kind !== 'app_failure' + || typeof a.applicationFailure.phase !== 'string' || !a.applicationFailure.phase + || typeof a.applicationFailure.reason !== 'string' || !a.applicationFailure.reason)) { + throw new Error('--application-failure-json must describe an application failure'); + } + a.out = privateGradingDirectory(a.app, a.out); + if (!Array.isArray(a.regressionChecks) + || a.regressionChecks.some(key => typeof key !== 'string' || !key)) { + throw new Error('--regression-checks-json must contain stable check keys'); + } + return a; +} + +export function selectObservationScope(selectedTask: BoundRecipeTaskRequestResult | null, + observation: Observation = 'scored'): Selection | null { + if (observation === 'scored') return selectedTask?.selection ?? null; + if (observation !== 'observed') throw new Error(`unknown observation scope ${observation}`); + if (!selectedTask || !isModularRecipeTaskRequest(selectedTask)) { + throw new Error('observed specifications require a modular schema-3 task request'); + } + const selection = selectedTask.selection; + if (!selection.observedChecks.length) throw new Error('observed specification scope is empty'); + return { + ...selection, + observation: 'observed', + checks: selection.observedChecks, + scoredPoints: 0, + observedPoints: selection.observedChecks.reduce((total, check) => total + check.points, 0), + }; +} + +export function attachRegressionScope(selection: Selection | null, recipeBinding: RecipeBinding | null, + declaredSuites: DeclaredSuite[], stableKeys: string[] = []): Selection | null { + if (!stableKeys.length) return selection; + if (!selection || !recipeBinding?.release?.checkCatalog) { + throw new Error('regression checks require a recipe-bound scored selection'); + } + const uniqueKeys = [...new Set(stableKeys)]; + if (uniqueKeys.length !== stableKeys.length) throw new Error('regression checks contain duplicates'); + const currentKeys = new Set(selection.checks.map(check => check.stableKey)); + const catalog = new Map(recipeBinding.release.checkCatalog + .map(check => [check.stableKey, check])); + const inheritedSuites = new Set(declaredSuites.filter(suite => suite.inherited) + .map(suite => suite.id)); + const regressionChecks = uniqueKeys.map(key => { + if (currentKeys.has(key)) throw new Error(`regression check ${key} is already in the current score`); + const check = catalog.get(key); + if (!check) throw new Error(`regression check ${key} is absent from the cumulative recipe`); + if (!inheritedSuites.has(check.executionId)) { + throw new Error(`regression check ${key} does not belong to an inherited execution`); + } + return { ...check, treatment: check.treatment ?? 'regression' }; + }); + const evaluationDocument = { schemaVersion: 1, selectionSha256: selection.sha256, + regressionChecks: uniqueKeys.slice().sort() }; + return { + ...selection, + checks: [...selection.checks, ...regressionChecks], + regressionChecks: regressionChecks.map(check => ({ ...check, treatment: check.treatment ?? 'regression' })), + regressionPoints: regressionChecks.reduce((total, check) => total + check.points, 0), + evaluationSha256: sha256(Buffer.from(canonicalDefinitionJson(evaluationDocument))), + }; +} + +const COMMAND_TIMEOUT_MS = GRADER_SOURCE_TIMEOUT_MS; +const run = (cmd: string, args: readonly string[], opts: Omit = {}): string => + execFileSync(cmd, args, { + encoding: 'utf8', stdio: 'pipe', cwd: ROOT, timeout: COMMAND_TIMEOUT_MS, ...opts, + }); + +export async function verifyApplicationProbe(url: string, { + fetchImpl = fetch, timeoutMs = 5000, +}: { fetchImpl?: ApplicationFetch; timeoutMs?: number } = {}): Promise { + let response; + try { + response = await fetchImpl(url, { signal: AbortSignal.timeout(timeoutMs) }); + } catch (error) { + return { ok: false, + detail: `application did not respond: ${error instanceof Error ? error.message : String(error)}` }; + } + if (!response.ok) { + return { ok: false, detail: `application returned HTTP ${response.status}` }; + } + return { ok: true, detail: null }; +} + +export async function waitForApplicationProbe(url: string, { + attempts = 9, intervalMs = 250, probeTimeoutMs = 1000, + probe = verifyApplicationProbe, sleepImpl = sleep, +}: { attempts?: number; intervalMs?: number; probeTimeoutMs?: number; + probe?: typeof verifyApplicationProbe; + sleepImpl?: (ms: number) => Promise } = {}): Promise { + if (!Number.isInteger(attempts) || attempts < 1) { + throw new Error('application probe attempts must be a positive integer'); + } + let result = null; + for (let attempt = 1; attempt <= attempts; attempt += 1) { + result = await probe(url, { timeoutMs: probeTimeoutMs }); + if (result.ok || attempt === attempts) return result; + await sleepImpl(intervalMs); + } + return result ?? { ok: false, detail: 'application readiness probe did not run' }; +} + +// Confirm the app uses the database leased to this run. +export function checkDatabaseProvenance(args: Pick): DatabaseProvenance { + const adapter = STACK_ADAPTER_REGISTRY.get(args.backend); + // Source text cannot prove which database the running app uses. Leased runs + // prove it with an application write, including container-local endpoints. + if (args.databaseLease && 'proveUse' in adapter.database) { + return { ok: true, reason: 'leased database requires runtime marker verification' }; + } + const expected = adapter.ports.allocations().db; + if (!expected) return { ok: true, reason: 'no external database for this backend' }; + // Neutral guidance does not prescribe project layout. Search the app for the + // connection string instead of assuming it is in server/.env. + const urls: string[] = []; + let usesLeasedEnvironment = false; + const walk = (dir: string): void => { + if (!existsSync(dir)) return; + for (const e of readdirSync(dir, { withFileTypes: true })) { + if (/^(node_modules|dist|\.vite|\.git|module_bindings)$/.test(e.name)) continue; + const p = join(dir, e.name); + if (e.isDirectory()) { walk(p); continue; } + if (!/\.(env|ts|tsx|js|mjs|json|yaml|yml)$|^\.env/.test(e.name)) continue; + try { + const text = readFileSync(p, 'utf8'); + if (/process\.env(?:\.DATABASE_URL|\[['"]DATABASE_URL['"]\])/.test(text)) { + usesLeasedEnvironment = true; + } + urls.push(...adapter.agent.findDatabaseUrls({ text })); + } catch { /* unreadable file proves nothing */ } + } + }; + walk(args.app); + if (usesLeasedEnvironment) { + return { ok: true, url: 'process.env.DATABASE_URL', + reason: 'app reads the database URL supplied by its authenticated backend lease' }; + } + if (!urls.length) return { ok: false, + reason: 'app neither reads process.env.DATABASE_URL nor contains a database connection string' }; + const matchesExpectedPort = (value: string): boolean => { + try { return Number(new URL(value).port) === Number(expected); } + catch { return false; } + }; + const ok = urls.some(matchesExpectedPort); + return { ok, url: urls[0], + reason: ok ? 'ok' : `app targets ${urls[0]} but the benchmark database is on port ${expected}` }; +} + +export async function writeApplicationDatabaseMarker( + args: Pick, + definition: DatabaseProvenanceDefinition, + { browser: suppliedBrowser }: { browser?: Browser } = {}, +): Promise { + if (!definition) throw new Error('track does not define runtime database provenance'); + const marker = `sb${randomUUID().replaceAll('-', '').slice(0, 16)}`; + const browser = suppliedBrowser ?? (args.browserWsEndpoint + ? await chromium.connect(args.browserWsEndpoint) + : await chromium.launch({ headless: true, ...attemptBrowserLaunchOptions() })); + try { + const context = await browser.newContext(); + try { + const page = await context.newPage(); + page.setDefaultTimeout(8000); + const actor = new Actor('database-provenance', page, context); + await actor.ready; + await runApplicationNavigation(() => page.goto(args.url, { waitUntil: 'domcontentloaded', timeout: 20000 })); + const evidence = await executeAction(ACTION_REGISTRY, definition.browserAction, + { do: definition.browserAction, actor: actor.name, name: marker, exact: true }, { + capabilities: { + actors: new Map([[actor.name, actor]]), + 'browser-interaction': { defaultWithin: 8000, + roomName: (name: string) => name, scopedUser: (name: string) => name, + testId: stableElementSelector, + sleep: (ms: number, signal: AbortSignal) => sleep(ms, undefined, { signal }), + }, + }, + onAbort: () => context.close(), + }); + if (evidence.status === 'passed') return { ok: true, marker }; + if (evidence.status === 'failed') return { ok: false, marker: null, + reason: evidence.summary ?? 'application signup failed during database provenance' }; + throw new Error(`database provenance signup ${evidence.status}: ${evidence.summary}`); + } finally { await context.close(); } + } catch (error) { + if (error instanceof ActionApplicationFailure) return { ok: false, marker: null, reason: error.message }; + throw error; + } finally { if (!suppliedBrowser) await browser.close(); } +} + +export function databaseProvenanceFailure(error: unknown): { kind: string; phase: string; reason: string } { + return { kind: 'harness_failure', phase: 'database-provenance', + reason: `runtime database provenance failed: ${error instanceof Error ? error.message : String(error)}` }; +} + +// A successful browser/provider flow is not evidence of an application database write. +export async function verifyApplicationDatabaseMarker( + args: Pick, + definition: DatabaseProvenanceDefinition, + { write = writeApplicationDatabaseMarker, read = checkRuntimeDatabaseProvenance } = {}, +): Promise<{ write: ProvenanceWrite; runtime: RuntimeProvenance | null }> { + const result = await write(args, definition); + return { write: result, runtime: result.ok ? read(args, result.marker) : null }; +} + +export function checkRuntimeDatabaseProvenance(args: Pick, + marker: string | null = null): RuntimeProvenance { + const adapter = STACK_ADAPTER_REGISTRY.get(args.backend); + if (!('proveUse' in adapter.database)) { + return { ok: null, verified: false, + reason: 'exact runtime database marker proof is not implemented for this stack' }; + } + if (!args.databaseLease) { + return { ok: null, verified: false, + reason: 'standalone grading has no authenticated database lease' }; + } + if (typeof marker !== 'string' || !marker) { + return { ok: null, verified: false, + reason: 'the application action did not produce a database marker' }; + } + if (args.backend === 'spacetime') { + return STACK_ADAPTER_REGISTRY.get('spacetime').database.proveUse( + { lease: requireLeasedSpacetime(args.databaseLease), marker }); + } + const lease = requireLeasedDatabase(args.databaseLease); + return args.backend === 'mongodb' + ? STACK_ADAPTER_REGISTRY.get('mongodb').database.proveUse({ lease, marker }) + : STACK_ADAPTER_REGISTRY.get('postgres').database.proveUse({ lease, marker }); +} + +function isGradePayload(value: GradePayload | LintPayload | null | undefined): value is GradePayload { + return value !== null && value !== undefined && 'total' in value && 'max' in value; +} + +// Report the application size and direct runtime dependency count. +export function codeMetrics(args: Pick): { serverLoc: number; serverFiles: number; + totalLoc: number; totalFiles: number; runtimeDeps: number } { + // Minimal-guidance apps may place server code outside the conventional directory. + const adapter = STACK_ADAPTER_REGISTRY.get(args.backend); + const conventional = adapter.agent.serverDirectory; + const SERVER_DIR = existsSync(join(args.app, conventional)) ? conventional : '.'; + const walk = (dir: string, out: string[] = []): string[] => { + if (!existsSync(dir)) return out; + for (const e of readdirSync(dir, { withFileTypes: true })) { + if (/^(node_modules|dist|\.vite|module_bindings|drizzle)$/.test(e.name)) continue; + const p = join(dir, e.name); + if (e.isDirectory()) walk(p, out); + // Count every supported JavaScript and TypeScript source extension. + else if (/\.(ts|tsx|js|jsx|mjs|cjs)$/.test(e.name)) out.push(p); + } + return out; + }; + const count = (files: string[]): number => files.reduce((n, f) => n + readFileSync(f, 'utf8').split('\n').length, 0); + // With no conventional server directory, "server" is everything that is not + // the client — otherwise the fallback counts the client twice and serverLoc + // equals totalLoc, which reads as a much larger backend than was written. + const allFiles = walk(args.app); + const serverFiles = SERVER_DIR === '.' + ? allFiles.filter(f => !/[\\/]client[\\/]/.test(f)) + : walk(join(args.app, SERVER_DIR)); + + let deps = 0; + const packageFiles = new Set([ + resolve(args.app, 'package.json'), + resolve(args.app, SERVER_DIR, 'package.json'), + resolve(args.app, 'client/package.json'), + ]); + for (const p of packageFiles) { + if (!existsSync(p)) continue; + try { deps += Object.keys(JSON.parse(readFileSync(p, 'utf8')).dependencies ?? {}).length; } catch { /* ignore */ } + } + + return { + serverLoc: count(serverFiles), serverFiles: serverFiles.length, + totalLoc: count(allFiles), totalFiles: allFiles.length, + runtimeDeps: deps, + }; +} + +export function findMutationBackups(app: string, { readDir = readdirSync }: + { readDir?: MutationDirectoryReader } = {}): string[] { + const backups: string[] = []; + const walk = (dir: string): void => { + let entries; + try { + entries = readDir(dir, { withFileTypes: true }); + } catch (error) { + // Vite atomically replaces transient dependency directories while the + // app runs. They are not source and may vanish between parent and child + // reads; a missing directory cannot contain a mutation backup. + if (isRecord(error) && error.code === 'ENOENT') return; + throw error; + } + for (const entry of entries) { + if (/^(node_modules|dist|\.vite|\.git|module_bindings)$/.test(entry.name)) continue; + const path = join(dir, entry.name); + if (entry.isDirectory()) walk(path); + else if (entry.isFile() && entry.name.endsWith('.mutation-backup')) backups.push(path); + } + }; + walk(app); + return backups; +} + +function resetDatabase(args: RunArguments): { ok: boolean; detail: string | null; + outcome: { kind: string; phase: string; appFailures?: string[] } | null } { + process.stdout.write(' reset database ... '); + try { + run(process.execPath, [RESET, args.backend, args.app]); + console.log('ok'); + } catch (err) { + console.log('FAILED'); + const failure: Failure = err instanceof Error ? err : new Error(String(err)); + const detail = childFailureDetail(failure, failure.stdout); + console.log(` ${detail}`); + return { ok: false, detail, outcome: resetFailureOutcome(failure) }; + } + return { ok: true, detail: null, outcome: null }; +} + +export function contractLintArgv(args: ContractLintArguments, + selectedTask: BoundRecipeTaskRequestResult | null = null): string[] { + const interfaces = selectedTask ? contractInterfaceNames(selectedTask.task.contractText) : []; + const out = join(args.out, ARTIFACT_FILE.contractLint); + return [compiledEntrypoint('linter', 'lint.js'), '--url', args.url, '--level', args.level, + '--track', args.track, '--label', args.label, '--out', out, + '--parent-attempt-id', args.bundleArtifactId, + ...(args.credentialAliases + ? ['--credential-aliases-json', JSON.stringify(args.credentialAliases)] : []), + ...(selectedTask ? ['--selected-hooks'] : []), + ...interfaces.flatMap(id => ['--hook', id])]; +} + +function lint(args: RunArguments, selectedTask: BoundRecipeTaskRequestResult | null = null): LintPayload | null { + process.stdout.write(' contract lint ... '); + const out = join(args.out, ARTIFACT_FILE.contractLint); + rmSync(out, { force: true }); + let failure: unknown = null; + try { + run('node', contractLintArgv(args, selectedTask)); + } catch (error) { failure = error; /* hook failures still write a report */ } + if (!existsSync(out)) { + const output = failure && typeof failure === 'object' && 'stdout' in failure + ? String(failure.stdout ?? '') : undefined; + const detail = failure instanceof Error + ? childFailureDetail(failure, output) : null; + throw new Error(`contract lint produced no report${detail ? `: ${detail}` : ''}`); + } + const r = readArtifactPayload(out, { expectedKind: 'contract_lint' }); + console.log(r.pass + ? r.counts.pass > 0 + ? `PASS (${r.counts.pass} interfaces)` + : r.counts.scenario > 0 + ? `DEFERRED (${r.counts.scenario} interfaces checked during feature grading)` + : 'NO STANDALONE INTERFACES SELECTED' + : `FAIL (${r.counts.fail} failed, ${r.counts.blocked} blocked)`); + return r; +} + +// Named write actions let concurrency checks issue authenticated operations +// without prescribing one transport. Missing actions are reported explicitly. +function checkActions(args: RunArguments): ActionsPayload | null { + process.stdout.write(` ${'actions'.padEnd(10)} ... `); + const out = join(args.out, ARTIFACT_FILE.actions); + rmSync(out, { force: true }); + try { + run('node', [compiledEntrypoint('commands', 'check-actions.js'), '--backend', args.backend, + '--url', args.url, '--app', args.app ?? '.', '--track', args.track, '--out', out, '--quiet', + '--parent-attempt-id', args.bundleArtifactId]); + } catch { /* non-zero exit means something is missing; the report still lands */ } + if (!existsSync(out)) { console.log('NO REPORT'); return null; } + const r = readArtifactPayload(out, { expectedKind: 'action_check' }); + if (!r.missing.length) { console.log(`all ${r.results.length} present`); return r; } + console.log(`${r.missing.length} MISSING — ${r.missing.join(', ')}`); + return r; +} + +async function gradeSuite(args: RunArguments, suite: DeclaredSuite, track: Track, + recipeBinding: RecipeBinding | null, bundleArtifactId: string, selectedChecks: RecipeCheck[] = [], + { recordSelection = true, captureMedia = true, outputDirectory = args.out }: { + recordSelection?: boolean; captureMedia?: boolean; outputDirectory?: string; + } = {}): Promise { + process.stdout.write(` ${suite.id.padEnd(10)} ... `); + mkdirSync(outputDirectory, { recursive: true }); + const out = join(outputDirectory, `grading-${suite.id}.json`); + rmSync(out, { force: true }); + const argv = [compiledEntrypoint('grader', 'grade.js'), '--url', args.url, '--level', args.level, + '--label', `${args.label}-${suite.id}`, '--out', out]; + if (suite.spec) argv.push('--spec', suite.spec); + argv.push('--backend', args.backend, '--track', args.track); + if (recipeBinding) argv.push('--expected-recipe-sha256', recipeBinding.release.contentSha256); + const requestedRecipe = args.recipe ?? (args.recipeTask + ? args.recipeTask.recipe.id : null); + if (requestedRecipe) argv.push('--recipe', requestedRecipe); + for (const check of selectedChecks) argv.push('--selected-check', check.stableKey); + if (args.credentialAliases) { + argv.push('--credential-aliases-json', JSON.stringify(args.credentialAliases)); + } + if (recordSelection && args.selection?.sha256) { + argv.push('--selection-sha256', args.selection.evaluationSha256 ?? args.selection.sha256); + } + argv.push('--parent-attempt-id', bundleArtifactId); + // The out-of-band write goes straight to this run's database, with no + // app code in the loop; only the harness knows which one that is. + argv.push('--db-name', databaseNameForGrading(track, args.runIndex ?? 0, + args.databaseLease?.resources.database ? args.databaseLease : null)); + if (args.restartSpec) argv.push('--restart-spec', JSON.stringify(args.restartSpec)); + // The systems criteria run scripts the app itself ships (back-office writes), + // so the grader has to know where the app lives. + if (args.app) argv.push('--app', args.app); + if (captureMedia && args.media) argv.push('--media', join(outputDirectory, 'media'), '--trace'); + else if (captureMedia) argv.push('--failure-media', join(outputDirectory, 'failure-media')); + if (args.browserWsEndpoint) argv.push('--browser-ws-endpoint', args.browserWsEndpoint); + const child = await runGraderChild(argv, outputDirectory, suite.id); + const { stdout, failure } = child; + if (!existsSync(out)) { + console.log('NO REPORT'); + const detail = childFailureDetail(failure, stdout); + throw new Error(`grader produced no report for ${suite.id}${detail ? `: ${detail}` : ''}; ` + + `full diagnostics: ${child.stdoutName}, ${child.stderrName}`); + } + const r = readArtifactPayload(out, { expectedKind: 'grade' }); + if (selectedChecks.length) { + const expected = selectedChecks.map(check => check.stableKey).sort(); + const reported = (r.selection?.checks ?? []).map(check => check.stableKey).sort(); + if (JSON.stringify(reported) !== JSON.stringify(expected)) { + throw new Error(`grader report scope differs from requested suite scope for ${suite.id}`); + } + } + console.log(`${r.total}/${r.max}`); + for (const f of r.features) { + for (const c of f.criteria.filter(c => !evidencePassed(criterionEvidence(c)))) { + console.log(` ${renderEvidenceConsoleLine(criterionEvidence(c), `${f.name} / ${c.id}`, { + includeSummary: false, + })}`); + } + } + // Disclose passes that lack server-side confirmation. + const uiOnly = r.features.flatMap(f => + f.criteria.filter(c => evidencePassed(criterionEvidence(c)) && c.serverCheck === 'unverified') + .map(c => `${f.name}/${c.id}`)); + if (uiOnly.length) { + console.log(` note: ${uiOnly.length} criterion/criteria passed on interface behaviour only`); + for (const u of uiOnly) console.log(` ${u} — server-side check not runnable on this backend`); + } + return r; +} + +export async function closeSuiteBrowser(browser: Pick | null, + bundle: Pick, persist: () => unknown): Promise { + try { await browser?.close(); } + catch (error) { + bundle.error = `grader browser shutdown failed: ${error instanceof Error ? error.message : String(error)}`; + bundle.outcome = { kind: 'harness_failure', phase: 'grading-cleanup', reason: bundle.error }; + persist(); + throw error; + } +} + +export function preserveStartFailure(error: unknown, out: string): void { + if (isRecord(error) && typeof error.startLog === 'string' && error.startLog) { + writeFileSync(join(out, 'application-start.log'), redactCredentials(error.startLog) + '\n'); + } +} + +async function main() { + const startedAt = new Date().toISOString(); + const args = parseArgs(process.argv); + args.databaseLease = databaseLeaseForGrading(args.backend); + const track = loadTrack(args.track); + const recipeBinding = resolveRecipeRelease(track, Number(args.level), args.recipeTask?.recipe ?? args.recipe); + if (!recipeBinding && (args.packIds.length || args.checkKeys.length)) { + throw new Error('--pack and --check require a recipe-bound level'); + } + const selectedTask = recipeBinding + ? (args.recipeTask + ? resolveBoundRecipeTaskRequest(recipeBinding, args.recipeTask) + : createBoundRecipeTaskRequest(recipeBinding, args)) + : null; + let selection = selectObservationScope(selectedTask, args.observation); + if (args.sourceSha256) { + const source = hashAppSource(args.app); + if (source.sha256 !== args.sourceSha256) { + throw new Error('live application source differs from the source selected for grading'); + } + } + const declaredSuites = recipeBinding + ? suitesForRecipe(track, recipeBinding) + : suitesFor(track, Number(args.level)); + if (args.observation === 'scored') { + selection = attachRegressionScope(selection, recipeBinding, declaredSuites, + args.regressionChecks); + } else if (args.regressionChecks.length) { + throw new Error('observed grading cannot include regression checks'); + } + args.selection = selection; + if (selection) { + const suiteIds = new Set(declaredSuites.map(suite => suite.id)); + const unmapped = selection.checks.filter(check => !suiteIds.has(check.executionId)); + if (unmapped.length) { + throw new Error(`selected recipe checks do not map to a declared suite: ${ + unmapped.map(check => check.stableKey).join(', ')}`); + } + } + const calibration = resolveCalibrationForRelease(recipeBinding?.release ?? null, { + trackRoot: track.dir, + stackBenchRoot: ROOT, + alias: `L${args.level}`, + }); + const observationSuffix = args.observation === 'observed' ? '-observed' : ''; + const bundleArtifactId = `${args.parentAttemptId ?? args.label}-grade-bundle-l${args.level}${observationSuffix}`; + args.bundleArtifactId = bundleArtifactId; + mkdirSync(args.out, { recursive: true }); + // Remove all prior grade output before writing cumulative evidence. + clearPreviousGradeOutputs(args.out); + + console.log(`\n=== ${args.label} (${args.backend}) ===`); + console.log(` app: ${args.app}`); + console.log(` url: ${args.url}`); + if (recipeBinding && selection) { + console.log(` recipe: ${recipeBinding.alias} -> ${recipeBinding.release.id} ` + + `(${recipeBinding.release.contentSha256.slice(0, 12)})`); + console.log(args.observation === 'observed' + ? ` scope: ${selection.checks.length} observed check(s), ${selection.observedPoints} observed point(s), 0 score contribution` + : ` scope: ${selection.checks.length} check(s), ${selection.scoredPoints} point(s)`); + if (selection.requested.packs?.length) console.log(` packs: ${selection.requested.packs.join(', ')}`); + if (selection.requested.features?.length) { + console.log(` features: ${selection.requested.features.join(', ')}`); + } + if (selection.requested.checks.length) console.log(` extra checks: ${selection.requested.checks.join(', ')}`); + } + + const bundle: Bundle = { + definitionSchemaVersion: track.schemaVersion, + recipeRelease: bundleRecipeRelease(recipeBinding), + calibration: calibration ? { id: calibration.id, + contentSha256: calibration.contentSha256 } : null, + label: args.label, track: args.track, backend: args.backend, url: args.url, app: args.app, + level: Number(args.level), observation: args.observation, + ...(args.sourceSha256 ? { source: { sha256: args.sourceSha256 } } : {}), + suites: {}, totals: {}, phaseTimings: [], + selection: selection ? { ...selection, attemptedChecks: [], reportedChecks: [], notRun: [] } : null, + }; + const selectedPackIds = new Set(selection?.checks.map(check => check.packId) ?? []); + const selectedPackDefinitions = recipeBinding?.plan.packs + .filter(pack => selectedPackIds.has(pack.id)) ?? []; + const writeBundle = () => { + const writeStarted = performance.now(); + if (args.sourceSha256) { + const current = hashAppSource(args.app); + if (current.sha256 !== args.sourceSha256) { + bundle.error = 'application source changed while grading was in progress'; + bundle.outcome = { kind: 'harness_failure', phase: 'source-provenance', + reason: bundle.error }; + } + } + const result = writeArtifact(join(args.out, ARTIFACT_FILE.gradeBundle), { + kind: 'grade_bundle', + id: bundleArtifactId, + attempt: { id: bundleArtifactId, parentId: args.parentAttemptId ?? null }, + timestamps: { startedAt, completedAt: new Date().toISOString() }, + identities: recipeArtifactIdentities(recipeBinding?.release ?? null, { + calibration: calibration ? { id: calibration.id, + sha256: calibration.contentSha256 } : null, + stackAdapter: { id: args.backend }, + }), + payload: bundle, + }); + console.log(` evidence write and source verification ... ${(performance.now() - writeStarted).toFixed(1)}ms`); + return result; + }; + const recordApplicationAbort = () => { + bundle.totals = applicationFailureTotals(selection, declaredSuites); + }; + const freshenFailureMessage = () => { + const detail = lastResetFailure ? `: ${lastResetFailure}` : ''; + if (lastResetOutcome?.phase !== 'application-readiness') { + return `database reset failed — scores would not be comparable${detail}`; + } + return lastResetOutcome.kind === 'harness_failure' + ? `application server stopped by the grader was not restored${detail}` + : `application did not become ready after database reset${detail}`; + }; + const markRemainingNotRun = (reason: string): void => { + if (!bundle.selection) return; + const accounted = new Set([ + ...bundle.selection.attemptedChecks, + ...bundle.selection.notRun.map(check => check.stableKey), + ]); + bundle.selection.notRun.push(...bundle.selection.checks + .filter(check => !accounted.has(check.stableKey)) + .map(check => ({ stableKey: check.stableKey, reason }))); + }; + + if (args.applicationFailure) { + bundle.error = args.applicationFailure.reason; + bundle.outcome = args.applicationFailure; + recordApplicationAbort(); + markRemainingNotRun(`run aborted: ${bundle.error}`); + writeBundle(); + console.log(`\nABORTED: ${bundle.error}`); + process.exit(1); + } + + // Reset before each stateful check. + let lastResetFailure: string | null = null; + let lastResetOutcome: ResetOutcome = { kind: 'harness_failure', phase: 'database-reset' }; + // Set when a grader stopped the application server and could not start it + // again. Until the harness starts it, the app cannot be blamed for being + // unreachable. + let applicationLeftStopped = false; + let timingSuite: string | null = null; + const measure = (phase: string, work: () => T | Promise) => + measurePhase(bundle.phaseTimings, phase, timingSuite, work); + const freshen = async () => { + if (!args.reset) return true; + const requiresReseed = STACK_ADAPTER_REGISTRY.get(args.backend).reset.requiresReseed; + const restartSpec = args.restartSpec; + if (track.reseedOnReset && requiresReseed && !restartSpec) { + lastResetFailure = `track ${args.track} requires --restart-spec to initialize the app after reset`; + lastResetOutcome = { kind: 'harness_failure', phase: 'application-reset-control' }; + return false; + } + if (track.reseedOnReset && restartSpec && requiresReseed) { + process.stdout.write(' stop application ... '); + try { + await measure('stop', () => controlAppServer(restartSpec, 'stop')); + applicationLeftStopped = true; + console.log('ok'); + } catch (error) { + const failure: Failure = error instanceof Error ? error : new Error(String(error)); + lastResetFailure = childFailureDetail(failure); + lastResetOutcome = { kind: 'harness_failure', phase: 'application-reset-control' }; + console.log(`FAILED (${lastResetFailure})`); + return false; + } + } + const reset = await measure('reset', () => resetDatabase(args)); + lastResetFailure = reset.detail; + lastResetOutcome = reset.outcome ?? { kind: 'harness_failure', phase: 'database-reset' }; + if (!reset.ok) return false; + // Do not grade until the reset application is reachable. + const waitUntilReady = async () => { + const ready = await measure('readiness', () => waitForApplicationProbe(args.url)); + if (!ready.ok) { + lastResetFailure = ready.detail; + lastResetOutcome = applicationLeftStopped + ? { kind: 'harness_failure', phase: 'application-readiness' } + : { kind: 'app_failure', phase: 'application-readiness', + appFailures: ['application-readiness'] }; + console.log(`FAILED (${ready.detail})`); + return false; + } + console.log('ok'); + return true; + }; + if (track.reseedOnReset && restartSpec && requiresReseed) { + process.stdout.write(' restart ... '); + // Judge restart success with the readiness probe. The restart command can + // leave a long-running server process behind, so the command also needs a deadline. + try { + // Do not give a background server an inherited pipe that keeps the + // synchronous restart command open. + await measure('start', () => controlAppServer(restartSpec, 'start')); + applicationLeftStopped = false; + } catch (err) { + preserveStartFailure(err, args.out); + const failure: Failure = err instanceof Error ? err : new Error(String(err)); + lastResetOutcome = resetFailureOutcome(failure); + const detail = ((failure.stderr || '') + (failure.stdout || '') + (failure.message || '')) + .toString().trim().split('\n').slice(-3).join(' | ').slice(0, 300); + lastResetFailure = detail || null; + console.log('FAILED (application did not restart)'); + console.log(` control: ${JSON.stringify(restartSpec)}`); + console.log(` ${detail}`); + return false; + } + return await waitUntilReady(); + } + process.stdout.write(' ready ... '); + return await waitUntilReady(); + }; + + bundle.code = codeMetrics(args); + console.log(` code ... ${bundle.code.serverLoc} server LOC in ${bundle.code.serverFiles} files, ` + + `${bundle.code.totalLoc} total LOC, ${bundle.code.runtimeDeps} runtime deps`); + + // Refuse source left modified by an interrupted mutation run. + const mutated = findMutationBackups(args.app); + if (mutated.length) { + bundle.error = `app still carries mutation backups (${mutated.join(', ')}) — its source is mutated, not the build under test`; + bundle.outcome = { kind: 'harness_failure', phase: 'mutation-cleanup', reason: bundle.error }; + markRemainingNotRun('run aborted because application source is still mutated'); + writeBundle(); + console.log(`\nABORTED: ${bundle.error}`); + process.exit(1); + } + + const prov = checkDatabaseProvenance(args); + bundle.provenance = prov; + console.log(` database ... ${prov.ok ? prov.reason : `WRONG DATABASE — ${prov.reason}`}`); + if (!prov.ok) { + bundle.error = `app is not using the benchmark database: ${prov.reason}`; + bundle.outcome = { kind: 'app_failure', phase: 'database-provenance', reason: bundle.error, + appFailures: ['database-provenance'] }; + recordApplicationAbort(); + markRemainingNotRun('run aborted because database provenance was invalid'); + writeBundle(); + console.log('\nABORTED: results would not describe the benchmark environment.'); + process.exit(1); + } + + if (args.observation === 'scored') { + if (!(await freshen())) { + bundle.error = freshenFailureMessage(); + bundle.outcome = { ...lastResetOutcome, reason: bundle.error }; + if (bundle.outcome.kind === 'app_failure') recordApplicationAbort(); + markRemainingNotRun(`run aborted: ${bundle.error}`); + writeBundle(); + console.log(`\nABORTED: ${bundle.error}`); + process.exit(1); + } + let runtime = checkRuntimeDatabaseProvenance(args); + let proofError = null; + let actionFailure: string | null = null; + const proof = track.databaseProvenance; + const supportsRuntimeProof = 'proveUse' in STACK_ADAPTER_REGISTRY.get(args.backend).database; + const requiresRuntimeProof = supportsRuntimeProof && args.databaseLease && args.reset; + if (requiresRuntimeProof && !proof) { + proofError = new Error(`${args.track} does not define a runtime database provenance check`); + } else if (requiresRuntimeProof && proof) { + try { + const result = await verifyApplicationDatabaseMarker(args, proof); + if (!result.write.ok) actionFailure = result.write.reason; + else if (result.runtime) runtime = result.runtime; + } catch (error) { + proofError = error; + } + + // The proof writes unique data through the application. Remove it before + // linting and scored grading so the proof cannot change the result. + if (!(await freshen())) { + bundle.error = freshenFailureMessage(); + bundle.outcome = { ...lastResetOutcome, reason: bundle.error }; + if (bundle.outcome.kind === 'app_failure') recordApplicationAbort(); + markRemainingNotRun(`run aborted: ${bundle.error}`); + writeBundle(); + console.log(`\nABORTED: ${bundle.error}`); + process.exit(1); + } + } else if (supportsRuntimeProof && !args.reset) { + runtime = { ok: null, verified: false, + reason: 'runtime marker proof requires database reset to isolate its write' }; + } + + if (!proofError && !actionFailure && supportsRuntimeProof && args.databaseLease && !runtime.verified) { + proofError = new Error(`leased database identity was not verified: ${runtime.reason}`); + } + if (proofError) { + bundle.outcome = databaseProvenanceFailure(proofError); + bundle.error = bundle.outcome.reason; + markRemainingNotRun('run aborted because runtime database provenance could not be verified'); + writeBundle(); + console.log(`\nABORTED: ${bundle.error}`); + process.exit(1); + } + + if (actionFailure) { + bundle.error = actionFailure; + bundle.outcome = { kind: 'app_failure', phase: 'database-provenance-action', + reason: actionFailure, appFailures: ['database-provenance-action'] }; + recordApplicationAbort(); + markRemainingNotRun('run aborted because the application database write failed'); + writeBundle(); + console.log(`\nABORTED: ${actionFailure}`); + process.exit(1); + } + + bundle.provenance.runtime = runtime; + console.log(` db runtime ... ${runtime.verified + ? runtime.ok ? runtime.reason : `WRONG DATABASE — ${runtime.reason}` + : runtime.reason}`); + if (runtime.ok === false) { + bundle.error = `app did not write its marker to the benchmark database: ${runtime.reason}`; + bundle.outcome = { kind: 'app_failure', phase: 'database-provenance', reason: bundle.error, + appFailures: ['database-provenance'] }; + recordApplicationAbort(); + markRemainingNotRun('run aborted because runtime database provenance failed'); + writeBundle(); + console.log('\nABORTED: application data came from outside the benchmark database.'); + process.exit(1); + } + try { + bundle.suites.lint = lint(args, selectedTask); + } catch (error) { + markRemainingNotRun('run aborted after contract lint failed to produce evidence'); + bundle.error = error instanceof Error ? error.message : String(error); + bundle.outcome = { kind: 'harness_failure', phase: 'contract-lint', reason: bundle.error }; + writeBundle(); + console.log(`\nABORTED: ${bundle.error}`); + process.exit(1); + } + bundle.actions = checkActions(args); + } + + // Keep current-level score separate from earlier guarantee regressions. + let total = 0, max = 0, regTotal = 0, regMax = 0; + const dirty = false; + let browserServer: BrowserServer | null = null; + try { + if (declaredSuites.some(suite => !selection + || selection.checks.some(check => check.executionId === suite.id))) { + browserServer = await chromium.launchServer({ headless: true, ...attemptBrowserLaunchOptions() }); + args.browserWsEndpoint = browserServer.wsEndpoint(); + } + for (const suite of declaredSuites) { + timingSuite = suite.id; + const selectedChecks = selection?.checks.filter(check => check.executionId === suite.id) ?? []; + if (selection && selectedChecks.length === 0) { + console.log(` ${suite.id.padEnd(10)} ... not selected`); + continue; + } + if (!(await freshen())) { + bundle.error = freshenFailureMessage(); + console.log(` ${suite.id}: SKIPPED (${bundle.error})`); + markRemainingNotRun(`run aborted: ${bundle.error}`); + bundle.outcome = { ...lastResetOutcome, reason: bundle.error }; + if (bundle.outcome.kind === 'app_failure') recordApplicationAbort(); + writeBundle(); + console.log(`\nABORTED: ${bundle.error}`); + throw new Error(bundle.error); + } + if (bundle.selection) { + bundle.selection.attemptedChecks.push(...selectedChecks.map(check => check.stableKey)); + } + let r; + try { + r = await measure('grader', () => gradeSuite(args, suite, track, recipeBinding, bundleArtifactId, selectedChecks)); + } catch (error) { + markRemainingNotRun(`run aborted after ${suite.id} grader failure`); + bundle.error = error instanceof Error ? error.message : String(error); + bundle.outcome = { kind: 'harness_failure', phase: `grade:${suite.id}`, reason: bundle.error }; + writeBundle(); + console.log(`\nABORTED: ${bundle.error}`); + throw error; + } + bundle.suites[suite.id] = r; + if (isGradePayload(r) && r.features.some(feature => feature.cleanupEvidence?.failures + .some(failure => failure.stage === 'application-restore'))) { + applicationLeftStopped = true; + } + if (bundle.selection) { + bundle.selection.reportedChecks.push(...selectedChecks.map(check => check.stableKey)); + } + if (selection) { + bundle.packRuntime = aggregatePackRuntime( + Object.values(bundle.suites).filter(isGradePayload), + selectedPackDefinitions); + const exceeded = exceededPackBudgets(bundle.packRuntime); + if (exceeded.length) { + // Runtime budgets qualify references; generated apps still receive a complete grade. + console.log(` runtime ... ${exceeded.map(pack => + `${pack.id} ${pack.measuredRuntimeMs}ms > ${pack.budget.maxRuntimeMs}ms`) + .join(', ')} [recorded; grading continues]`); + } + } + if (suite.inherited) { regTotal += r.total; regMax += r.max; } + else { total += r.total; max += r.max; } + } + } finally { + args.browserWsEndpoint = undefined; + await closeSuiteBrowser(browserServer, bundle, writeBundle); + } + + bundle.totals = { + score: total, max, dirty, contractPass: isGradePayload(bundle.suites.lint) + ? null : bundle.suites.lint?.pass ?? null, + // null rather than 0/0 at L1, where there is nothing earlier to regress. + regression: regMax ? { score: regTotal, max: regMax } : null, + }; + writeBundle(); + + console.log(` ${'TOTAL'.padEnd(10)} ... ${total}/${max}${dirty ? ' [DIRTY]' : ''}`); + if (regMax) { + const kept = regTotal === regMax ? 'all earlier guarantees still hold' : `${regMax - regTotal} EARLIER GUARANTEE(S) LOST`; + console.log(` ${'REGRESSION'.padEnd(10)} ... ${regTotal}/${regMax} — ${kept}`); + } + console.log(` bundle: ${join(args.out, ARTIFACT_FILE.gradeBundle)}`); +} + +if (process.argv[1] && pathToFileURL(resolve(process.argv[1])).href === import.meta.url) main(); diff --git a/tools/stack-bench/commands/test-loop.ts b/tools/stack-bench/commands/test-loop.ts new file mode 100644 index 00000000000..3192f2ce3ef --- /dev/null +++ b/tools/stack-bench/commands/test-loop.ts @@ -0,0 +1,310 @@ +#!/usr/bin/env node +import { privateGradingDirectory } from '../src/evidence/repair-evidence.js'; + +import { execFileSync, spawnSync } from 'node:child_process'; +import { readFileSync, existsSync, rmSync, mkdirSync, mkdtempSync, readdirSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; + +import { ARTIFACT_FILE, readArtifact, readArtifactPayload } from '../src/evidence/artifacts.js'; +import type { ArtifactIdentities } from '../src/evidence/artifacts.js'; +import type { CostRun, CostSession } from '../src/evidence/cost-proof.js'; +import type { PublicBackendLease } from '../src/runtime/backend-lease.js'; +import type { RepairLevel, RepairOutcome } from '../src/runtime/repair-grant.js'; +import type { LevelCheckpoint } from '../src/runtime/source-checkpoint.js'; +import { CODING_CONTAINER_BUG_REPORT_FILE } from '../src/runtime/coding-container-policy.js'; + +import { STACK_BENCH_ROOT as ROOT, compiledEntrypoint } from '../src/package-root.js'; +const WORK = mkdtempSync(join(tmpdir(), 'stack-bench-loop-')); +const APP = join(WORK, 'app'); +// A cold Playwright start plus two grades can exceed three minutes on Windows +// Docker hosts. The timeout is a deadlock guard, not a performance assertion. +const BENCH_TIMEOUT_MS = 300_000; + +interface LoopSession extends CostSession { + sessionId?: string; + tokens?: number; + turns?: number; + durationMs?: number; +} + +interface LoopLevel extends RepairLevel { + buildSessions?: LoopSession[]; + repairSessions?: LoopSession[]; + resumeSession?: LoopSession; + contractPass?: boolean; + stalled?: boolean; + code?: { totalLoc?: number }; + sessionTotals?: { sessions?: number; tokens?: number; turns?: number; durationMs?: number }; +} + +interface LoopRun extends CostRun { + id?: string; + levels?: LoopLevel[]; + outcome?: RepairOutcome; + artifactEnvelope?: { identities?: ArtifactIdentities }; + backendLease?: PublicBackendLease; + totals?: CostRun['totals'] & { max?: number; sessions?: number; tokens?: number; turns?: number; + modelDurationMs?: number; durationSec?: number }; +} + +interface GradeFeature { + id?: string; + setupEvidence?: { schemaVersion?: number; status?: string }; + criteria?: { evidence?: { schemaVersion?: number; status?: string; actions?: unknown[] } }[]; +} + +interface GradePayload { features?: GradeFeature[]; } +interface SourceCheckpointPayload { source: LevelCheckpoint; } +interface RepairContinuation { + baseline?: { reproduced?: boolean; score?: number; sourceSha256?: string }; + cumulativeRepairsBefore?: number; + cumulativeRepairsAfter?: number; + resumeSetup?: { sourceVerified?: boolean }; +} +interface RepairContinuationPayload extends LoopRun { continuation?: RepairContinuation; } + +function isRecord(value: unknown): value is Record { + return value !== null && typeof value === 'object' && !Array.isArray(value); +} + +function processOutput(error: unknown): string { + if (!isRecord(error)) return String(error); + return `${String(error.stdout ?? '')}${String(error.stderr ?? '')}`; +} + +// A failed assertion or interrupted CI job must not leave a fixture app that a +// later loop can mistake for its own output. +process.on('exit', () => rmSync(WORK, { recursive: true, force: true })); + +let failures = 0; +const check = (name: string, ok: boolean, detail = ''): void => { + console.log(` ${ok ? 'PASS' : 'FAIL'} ${name}${ok || !detail ? '' : ` — ${detail}`}`); + if (!ok) failures += 1; +}; + +function runBench(extra: string[] = []): string { + const argv = [compiledEntrypoint('commands', 'bench.js'), '--backend', 'stub', '--levels', '1', + '--agent-adapter', 'deterministic', + '--app', APP, '--out', WORK, + '--track', 'loop', + '--url', `file:///${join(APP, 'index.html').replace(/\\/g, '/')}`, ...extra]; + try { + return execFileSync('node', argv, { + encoding: 'utf8', + maxBuffer: 32 * 1024 * 1024, + timeout: BENCH_TIMEOUT_MS, + killSignal: 'SIGTERM', + }); + } catch (error: unknown) { return processOutput(error); } +} + +const invalidRounds = spawnSync('node', [compiledEntrypoint('commands', 'bench.js'), '--backend', 'stub', + '--repairs', '1.5'], + { encoding: 'utf8' }); +check('fractional correction budgets are rejected before a run starts', + invalidRounds.status !== 0 + && /--repairs must be a non-negative safe integer/.test(invalidRounds.stderr)); + +rmSync(WORK, { recursive: true, force: true }); +mkdirSync(APP, { recursive: true }); + +console.log('\nLoop test — one repair available'); +const out = runBench(['--repairs', '1']); +const runPath = join(WORK, ARTIFACT_FILE.run); + +check(`the benchmark run produced ${ARTIFACT_FILE.run}`, existsSync(runPath)); +if (!existsSync(runPath)) { + console.log(`\ncannot continue without ${ARTIFACT_FILE.run}`); + process.exit(1); +} + +const run = readArtifactPayload(runPath); +const level = run.levels?.[0]; +const evidenceDir = privateGradingDirectory(APP); +const bundleArtifact = readArtifact(join(evidenceDir, ARTIFACT_FILE.gradeBundle), + { expectedKind: 'grade_bundle' }); +const lintArtifact = readArtifact(join(evidenceDir, ARTIFACT_FILE.contractLint), + { expectedKind: 'contract_lint' }); +const actionArtifact = readArtifact(join(evidenceDir, ARTIFACT_FILE.actions), + { expectedKind: 'action_check' }); +const gradeArtifact = readArtifact(join(evidenceDir, 'grading-features.json'), { expectedKind: 'grade' }); +const leaseArtifact = readArtifact(join(WORK, ARTIFACT_FILE.backendLease), + { expectedKind: 'backend_lease_evidence' }); +const checkpointArtifact = readArtifact(join(WORK, 'level-l1-checkpoint.json'), + { expectedKind: 'source_checkpoint' }); + +check('recorded exactly one level', run.levels?.length === 1); +check('run and level carry structured outcomes', + typeof run.outcome?.kind === 'string' && run.outcome.kind === level?.outcome?.kind, + `run=${run.outcome?.kind} level=${level?.outcome?.kind}`); +check('artifacts carry the producing run id', typeof run.id === 'string' && run.id.length > 10); +check('run envelope identifies engine, agent adapter, and stack adapter', + /^[a-f0-9]{64}$/.test(run.artifactEnvelope?.identities?.engine?.sha256 ?? '') + && /^[a-f0-9]{64}$/.test(run.artifactEnvelope?.identities?.agentAdapter?.sha256 ?? '') + && run.artifactEnvelope?.identities?.stackAdapter?.id === 'stub'); +check('bundle is a child of the run', bundleArtifact.attempt.parentId === run.id, + JSON.stringify(bundleArtifact.attempt)); +check('public lease evidence is a child of the run', leaseArtifact.attempt.parentId === run.id, + JSON.stringify(leaseArtifact.attempt)); +check('level source checkpoint is hash-bound and linked to the run', + checkpointArtifact.attempt.parentId === run.id + && level?.checkpoint?.artifact === 'level-l1-checkpoint.json' + && level.checkpoint.sha256 === checkpointArtifact.payload.source.sha256 + && /^[a-f0-9]{64}$/.test(level.checkpoint.sha256) + && existsSync(join(WORK, level.checkpoint.directory)), + JSON.stringify(level?.checkpoint)); +check('lint, action, and grade evidence are children of the bundle', + [lintArtifact, actionArtifact, gradeArtifact] + .every(artifact => artifact.attempt.parentId === bundleArtifact.attempt.id)); +const gradedFeatures = gradeArtifact.payload?.features ?? []; +check('grade artifacts retain typed setup, criterion, and action evidence', + gradedFeatures.length > 0 + && gradedFeatures.every(feature => feature.setupEvidence?.schemaVersion === 1 + && (feature.criteria ?? []).every(criterion => criterion.evidence?.schemaVersion === 1 + && Array.isArray(criterion.evidence.actions))), + JSON.stringify(gradedFeatures.map(feature => ({ id: feature.id, + setup: feature.setupEvidence?.status, + criteria: feature.criteria?.map(criterion => criterion.evidence?.status) })))); +const publicJson = [runPath, join(WORK, ARTIFACT_FILE.backendLease), + join(evidenceDir, ARTIFACT_FILE.gradeBundle), join(evidenceDir, ARTIFACT_FILE.contractLint), + join(evidenceDir, ARTIFACT_FILE.actions), join(evidenceDir, 'grading-features.json')] + .map(path => readFileSync(path, 'utf8')).join('\n'); +check('public envelopes contain no secret or lease-token fields', + !/"(?:apiKey|leaseToken|ownershipToken|password|secret)"\s*:/i.test(publicJson)); +check('backend lease was released', + ['released', 'stopped'].includes(run.backendLease?.state ?? '') + && (run.backendLease?.resources?.locks?.every(lock => lock.releasedAt) ?? false), + JSON.stringify(run.backendLease?.state)); +check('a repair ran', level?.repairs === 1, `repairs=${level?.repairs}`); +check('successful repair is explicit', level?.repair?.status === 'corrected' + && level.repair.limit === 1 && level.repair.used === 1 + && level.repair.stopReason === 'passed', + JSON.stringify(level?.repair)); +const reportPath = join(APP, CODING_CONTAINER_BUG_REPORT_FILE); +const reportExists = existsSync(reportPath); +check('the bug report was written', reportExists); +// Behavioural findings must never reveal how they were detected, or a fix can +// target the check instead of the app. Missing-control findings are exempt: +// there the element id is the requirement. +const report = reportExists ? readFileSync(reportPath, 'utf8') : ''; +const behaviourSection = report.split('## Application interface')[0] ?? ''; +check('behavioural findings do not leak selectors or timings', + !/data-(?:role|testid)|locator|within \d+ms/.test(behaviourSection)); +check('missing interfaces are reported separately', /## Application interface/.test(report)); +check('build and fix costs are both recorded', + (level?.buildCostUsd ?? 0) > 0 && (level?.repairCostUsd ?? 0) > 0, + `build=${level?.buildCostUsd} fix=${level?.repairCostUsd}`); +check('build and fix sessions remain individually auditable', + level?.buildSessions?.length === 1 + && level.buildSessions[0]?.sessionId === 'stub-build' + && level?.repairSessions?.length === 1 + && level.repairSessions[0]?.sessionId === 'stub-fix', + JSON.stringify({ builds: level?.buildSessions, fixes: level?.repairSessions })); +check('level session totals include the build and fix', + level?.sessionTotals?.sessions === 2 + && level.sessionTotals.tokens === 2000 + && level.sessionTotals.turns === 5 + && level.sessionTotals.durationMs === 100, + JSON.stringify(level?.sessionTotals)); +check('grading produced a score out of a maximum', Number.isInteger(level?.score) && (level?.max ?? 0) > 0, + `${level?.score}/${level?.max}`); +check('code metrics captured', Boolean(level?.code) && typeof level?.code?.totalLoc === 'number', + JSON.stringify(level?.code)); +check('totals aggregate the levels', run.totals?.max === level?.max); +check('run totals aggregate every model session', + run.totals?.sessions === 2 && run.totals.tokens === 2000 + && run.totals.turns === 5 && run.totals.modelDurationMs === 100, + JSON.stringify(run.totals)); +check('wall time recorded', (run.totals?.durationSec ?? -1) >= 0); +check('the fix improved the contract lint', + /APPLICATION CONTRACT FAIL[\s\S]*APPLICATION CONTRACT PASS/.test(out) + || level?.contractPass === true, + 'expected the broken fixture to fail the lint and the fixed one to pass'); + +console.log('\nLoop test — zero repairs allowed'); +rmSync(WORK, { recursive: true, force: true }); +mkdirSync(APP, { recursive: true }); +runBench(['--repairs', '0']); +const capped = readArtifactPayload(runPath); +check('no fix ran when the cap is zero', capped.levels?.[0]?.repairs === 0); +check('no bug report was written when no fix is allowed', + !existsSync(join(APP, CODING_CONTAINER_BUG_REPORT_FILE))); + +console.log('\nLoop test - flat corrections exhaust their declared budget'); +rmSync(WORK, { recursive: true, force: true }); +mkdirSync(APP, { recursive: true }); +runBench(['--repairs', '2', '--model', 'deterministic-stall']); +const exhausted = readArtifactPayload(runPath); +const exhaustedLevel = exhausted.levels?.[0]; +check('both correction rounds ran after the first flat result', exhaustedLevel?.repairs === 2, + `repairs=${exhaustedLevel?.repairs}`); +check('an unresolved app records budget exhaustion', exhaustedLevel?.repair?.status === 'budget-exhausted' + && exhaustedLevel.repair.limit === 2 && exhaustedLevel.repair.used === 2 + && exhaustedLevel.repair.stopReason === 'budget-exhausted' + && exhaustedLevel.stalled === true && exhausted.outcome?.kind === 'app_failure', + JSON.stringify({ repair: exhaustedLevel?.repair, outcome: exhausted.outcome })); + +console.log('\nLoop test - a later finite grant continues the exact exhausted source'); +rmSync(WORK, { recursive: true, force: true }); +mkdirSync(APP, { recursive: true }); +runBench(['--repairs', '2', '--model', 'deterministic-deferred']); +const parentBefore = readFileSync(runPath, 'utf8'); +const deferred = readArtifactPayload(runPath); +check('the deferred parent exhausted its original two-round budget', + deferred.levels?.[0]?.repair?.status === 'budget-exhausted' + && deferred.levels[0].repair.used === 2, + JSON.stringify(deferred.levels?.[0]?.repair)); +let continuationOutput = ''; +try { + continuationOutput = execFileSync('node', [join(ROOT, 'dist', 'commands', 'repair-cli.js'), 'grant', WORK, + '--level', '1', '--repairs', '2', '--timeout-minutes', '10'], { + encoding: 'utf8', maxBuffer: 32 * 1024 * 1024, timeout: BENCH_TIMEOUT_MS, + }); +} catch (error: unknown) { + continuationOutput = processOutput(error); +} +const continuationRoot = join(WORK, 'continuations'); +const continuationDirectories = existsSync(continuationRoot) + ? readdirSync(continuationRoot, { withFileTypes: true }).filter(entry => entry.isDirectory()) : []; +const continuationDirectory = continuationDirectories.length === 1 + ? join(continuationRoot, continuationDirectories[0]?.name ?? '') : null; +const continuationPath = continuationDirectory + ? join(continuationDirectory, ARTIFACT_FILE.run) : null; +check('repair grant produced one linked continuation', + continuationPath !== null && existsSync(continuationPath), continuationOutput.slice(-2000)); +if (continuationDirectory && continuationPath && existsSync(continuationPath)) { + const continuationArtifact = readArtifact(continuationPath, { expectedKind: 'repair_continuation' }); + const continuation = continuationArtifact.payload; + const continuedLevel = continuation.levels?.[0]; + const continuationDetails = continuation.continuation; + const deferredLevel = deferred.levels?.[0]; + check('continuation reproduced the exact failed baseline before spending a repair', + continuationDetails?.baseline?.reproduced === true + && continuationDetails.baseline.score === deferredLevel?.score + && continuationDetails.baseline.sourceSha256 === deferredLevel?.checkpoint?.sha256, + JSON.stringify(continuationDetails?.baseline)); + check('continuation reached correctness inside its finite added budget', + continuation.outcome?.kind === 'passed' + && continuedLevel?.repair?.status === 'corrected' + && continuedLevel.repair.used === 1 + && continuationDetails?.cumulativeRepairsBefore === 2 + && continuationDetails?.cumulativeRepairsAfter === 3, + JSON.stringify({ repair: continuedLevel?.repair, continuation: continuationDetails })); + check('resume setup is visible, separately costed, and does not consume a repair', + continuationDetails?.resumeSetup?.sourceVerified === true + && continuedLevel?.resumeSession?.sessionId === 'stub-resume' + && (continuedLevel?.resumeCostUsd ?? 0) > 0 + && continuedLevel.repairs === 1, + JSON.stringify({ setup: continuationDetails?.resumeSetup, + resume: continuedLevel?.resumeSession, fixes: continuedLevel?.repairs })); + check('continuation process outcome is retained as a typed child artifact', + readArtifact(join(continuationDirectory, ARTIFACT_FILE.process), + { expectedKind: 'repair_process' }).attempt.parentId === deferred.id); +} +check('grant left the original run artifact byte-for-byte unchanged', + readFileSync(runPath, 'utf8') === parentBefore); + +rmSync(WORK, { recursive: true, force: true }); +console.log(`\n${failures === 0 ? 'loop OK' : `${failures} check(s) failed`}`); +process.exit(failures === 0 ? 0 : 1); diff --git a/tools/stack-bench/conditions/catalog.json b/tools/stack-bench/conditions/catalog.json new file mode 100644 index 00000000000..c88e06cf670 --- /dev/null +++ b/tools/stack-bench/conditions/catalog.json @@ -0,0 +1,16 @@ +{ + "schemaVersion": 1, + "kind": "study-condition-catalog", + "guidanceProfiles": { + "model-free-stub": "guidance/model-free-stub.json", + "prescribed": "guidance/prescribed.json", + "neutral": "guidance/neutral.json", + "neutral-dev": "guidance/neutral-dev.json", + "neutral-dev-no-sdk": "guidance/neutral-dev-no-sdk.json", + "neutral-managed-dev": "guidance/neutral-managed-dev.json", + "neutral-no-sdk": "guidance/neutral-no-sdk.json" + }, + "repairPolicies": { + "scored-only": "repairs/scored-only.json" + } +} diff --git a/tools/stack-bench/conditions/guidance/model-free-stub.json b/tools/stack-bench/conditions/guidance/model-free-stub.json new file mode 100644 index 00000000000..ffd536b8c02 --- /dev/null +++ b/tools/stack-bench/conditions/guidance/model-free-stub.json @@ -0,0 +1,20 @@ +{ + "schemaVersion": 1, + "kind": "backend-guidance-profile", + "id": "model-free-stub", + "mode": "neutral", + "material": { + "accessFacts": true, + "apiReference": false, + "designAdvice": false + }, + "documents": { + "stub": "backends/model-free-stub.md" + }, + "applicationInterfaces": { + "stub": "http" + }, + "skills": { + "stub": [] + } +} diff --git a/tools/stack-bench/conditions/guidance/neutral-dev-no-sdk.json b/tools/stack-bench/conditions/guidance/neutral-dev-no-sdk.json new file mode 100644 index 00000000000..69a8148748d --- /dev/null +++ b/tools/stack-bench/conditions/guidance/neutral-dev-no-sdk.json @@ -0,0 +1,31 @@ +{ + "schemaVersion": 1, + "kind": "backend-guidance-profile", + "id": "neutral-dev-no-sdk", + "mode": "neutral", + "material": { + "accessFacts": true, + "apiReference": true, + "designAdvice": true + }, + "documents": { + "mongodb": "backends/minimal/mongodb.md", + "postgres": "backends/minimal/postgres.md", + "spacetime": "backends/minimal/spacetime.md" + }, + "applicationInterfaces": { + "mongodb": "http", + "postgres": "http", + "spacetime": "reducer" + }, + "skills": { + "mongodb": [], + "postgres": [], + "spacetime": ["spacetime-dev"] + }, + "credentialAliases": { + "stackbench-admin-2026": "store-admin-2026", + "stackbench-customer-2026": "store-customer-2026", + "stackbench-staff-2026": "store-staff-2026" + } +} diff --git a/tools/stack-bench/conditions/guidance/neutral-dev.json b/tools/stack-bench/conditions/guidance/neutral-dev.json new file mode 100644 index 00000000000..dc66c4ebab9 --- /dev/null +++ b/tools/stack-bench/conditions/guidance/neutral-dev.json @@ -0,0 +1,36 @@ +{ + "schemaVersion": 1, + "kind": "backend-guidance-profile", + "id": "neutral-dev", + "mode": "neutral", + "material": { + "accessFacts": true, + "apiReference": true, + "designAdvice": true + }, + "documents": { + "mongodb": "backends/minimal/mongodb.md", + "postgres": "backends/minimal/postgres.md", + "spacetime": "backends/minimal/spacetime.md" + }, + "applicationInterfaces": { + "mongodb": "http", + "postgres": "http", + "spacetime": "reducer" + }, + "skills": { + "mongodb": [], + "postgres": [], + "spacetime": [ + "typescript-server", + "typescript-client", + "cli", + "spacetime-dev" + ] + }, + "credentialAliases": { + "stackbench-admin-2026": "store-admin-2026", + "stackbench-customer-2026": "store-customer-2026", + "stackbench-staff-2026": "store-staff-2026" + } +} diff --git a/tools/stack-bench/conditions/guidance/neutral-managed-dev.json b/tools/stack-bench/conditions/guidance/neutral-managed-dev.json new file mode 100644 index 00000000000..02c0ce1afa3 --- /dev/null +++ b/tools/stack-bench/conditions/guidance/neutral-managed-dev.json @@ -0,0 +1,36 @@ +{ + "schemaVersion": 1, + "kind": "backend-guidance-profile", + "id": "neutral-managed-dev", + "mode": "neutral", + "material": { + "accessFacts": true, + "apiReference": true, + "designAdvice": true + }, + "documents": { + "mongodb": "backends/minimal/mongodb.md", + "postgres": "backends/minimal/postgres.md", + "spacetime": "backends/minimal/spacetime.md" + }, + "applicationInterfaces": { + "mongodb": "http", + "postgres": "http", + "spacetime": "reducer" + }, + "skills": { + "mongodb": [], + "postgres": [], + "spacetime": [ + "typescript-server", + "typescript-client", + "cli", + "spacetime-managed-dev" + ] + }, + "credentialAliases": { + "stackbench-admin-2026": "store-admin-2026", + "stackbench-customer-2026": "store-customer-2026", + "stackbench-staff-2026": "store-staff-2026" + } +} diff --git a/tools/stack-bench/conditions/guidance/neutral-no-sdk.json b/tools/stack-bench/conditions/guidance/neutral-no-sdk.json new file mode 100644 index 00000000000..03011fb4f4d --- /dev/null +++ b/tools/stack-bench/conditions/guidance/neutral-no-sdk.json @@ -0,0 +1,31 @@ +{ + "schemaVersion": 1, + "kind": "backend-guidance-profile", + "id": "neutral-no-sdk", + "mode": "neutral", + "material": { + "accessFacts": true, + "apiReference": true, + "designAdvice": true + }, + "documents": { + "mongodb": "backends/minimal/mongodb.md", + "postgres": "backends/minimal/postgres.md", + "spacetime": "backends/minimal/spacetime.md" + }, + "applicationInterfaces": { + "mongodb": "http", + "postgres": "http", + "spacetime": "reducer" + }, + "skills": { + "mongodb": [], + "postgres": [], + "spacetime": [] + }, + "credentialAliases": { + "stackbench-admin-2026": "store-admin-2026", + "stackbench-customer-2026": "store-customer-2026", + "stackbench-staff-2026": "store-staff-2026" + } +} diff --git a/tools/stack-bench/conditions/guidance/neutral.json b/tools/stack-bench/conditions/guidance/neutral.json new file mode 100644 index 00000000000..53fa896918f --- /dev/null +++ b/tools/stack-bench/conditions/guidance/neutral.json @@ -0,0 +1,35 @@ +{ + "schemaVersion": 1, + "kind": "backend-guidance-profile", + "id": "neutral", + "mode": "neutral", + "material": { + "accessFacts": true, + "apiReference": true, + "designAdvice": true + }, + "documents": { + "mongodb": "backends/minimal/mongodb.md", + "postgres": "backends/minimal/postgres.md", + "spacetime": "backends/minimal/spacetime.md" + }, + "applicationInterfaces": { + "mongodb": "http", + "postgres": "http", + "spacetime": "reducer" + }, + "skills": { + "mongodb": [], + "postgres": [], + "spacetime": [ + "typescript-server", + "typescript-client", + "cli" + ] + }, + "credentialAliases": { + "stackbench-admin-2026": "store-admin-2026", + "stackbench-customer-2026": "store-customer-2026", + "stackbench-staff-2026": "store-staff-2026" + } +} diff --git a/tools/stack-bench/conditions/guidance/prescribed.json b/tools/stack-bench/conditions/guidance/prescribed.json new file mode 100644 index 00000000000..201760e0783 --- /dev/null +++ b/tools/stack-bench/conditions/guidance/prescribed.json @@ -0,0 +1,31 @@ +{ + "schemaVersion": 1, + "kind": "backend-guidance-profile", + "id": "prescribed", + "mode": "prescribed", + "material": { + "accessFacts": true, + "apiReference": true, + "designAdvice": true + }, + "documents": { + "mongodb": "backends/mongodb.md", + "postgres": "backends/postgres.md", + "spacetime": "backends/spacetime.md" + }, + "applicationInterfaces": { + "mongodb": "http", + "postgres": "http", + "spacetime": "reducer" + }, + "skills": { + "mongodb": [], + "postgres": [], + "spacetime": ["typescript-server", "typescript-client", "cli"] + }, + "credentialAliases": { + "stackbench-admin-2026": "store-admin-2026", + "stackbench-customer-2026": "store-customer-2026", + "stackbench-staff-2026": "store-staff-2026" + } +} diff --git a/tools/stack-bench/conditions/repairs/scored-only.json b/tools/stack-bench/conditions/repairs/scored-only.json new file mode 100644 index 00000000000..e3fc69b24af --- /dev/null +++ b/tools/stack-bench/conditions/repairs/scored-only.json @@ -0,0 +1,8 @@ +{ + "schemaVersion": 1, + "kind": "repair-policy", + "id": "scored-only", + "scoredEvidence": true, + "observedEvidence": false, + "scenarioValues": "failed-observations" +} diff --git a/tools/stack-bench/container/Dockerfile b/tools/stack-bench/container/Dockerfile new file mode 100644 index 00000000000..eb169e54d3a --- /dev/null +++ b/tools/stack-bench/container/Dockerfile @@ -0,0 +1,50 @@ +# The image a generated app is built in. +# +# The generated app must not see the harness, grader, or test definitions. +# +# No harness, grader, or test definition is copied in or mounted at run time. +# An adapter can mount only its selected stack artifacts, read-only. +# Keep the readable tag, but bind the base to an exact manifest. Campaigns use +# the digest of the completed image, so every attempt runs the same artifact. +FROM node:22-slim@sha256:f86be15afa9a8277608e141ce2a8aa55d3d9c40845921b8511f4fb7897be2554 + +# git: builds initialise repositories and some tooling shells out to it. +# curl: readiness probes against the app's own dev server. +# ca-certificates: TLS for npm and the API. +# procps: the build starts and stops its own dev servers. +# lsof: `kill-port` locates a listener with lsof on Linux, and finds nothing +# without it — it then prints "Process on port N killed" and exits 0 while the +# server keeps running. Every durability and deploy-window test would pass +# without restarting anything, which is worse than failing. None of lsof, fuser, +# ss or netstat is present in node:22-slim. +RUN apt-get update && apt-get install -y --no-install-recommends \ + git curl ca-certificates procps lsof chromium util-linux \ + && rm -rf /var/lib/apt/lists/* + +# Browser testing uses the system browser; no downloads into the agent home are needed. +ENV CHROME_BIN=/usr/bin/chromium +COPY browser-tools/package*.json /opt/browser-tools/ +RUN npm ci --prefix /opt/browser-tools --omit=dev --ignore-scripts \ + && node -e "require('/opt/browser-tools/node_modules/puppeteer-core')" + +# Pinned, and the auto-updater disabled: a CLI that updates itself mid-series +# changes the thing under test between one backend and the next. Override at +# build time to move deliberately rather than by drift. +ARG CLAUDE_VERSION=2.1.226 +ARG CODEX_VERSION=0.153.4 +ENV DISABLE_AUTOUPDATER=1 +RUN npm install -g @anthropic-ai/claude-code@${CLAUDE_VERSION} \ + && claude --version +RUN npm install -g @openai/codex@${CODEX_VERSION} && codex --version + +# The coding session can change the app and its own temporary state. It does +# not run as root, so it cannot change the system or harness control files. +RUN useradd --uid 10001 --create-home --shell /bin/bash developer \ + && chmod 0700 /home/developer + +# The app under construction. Everything the build writes lives here, and the +# host mounts its own work directory over it. +WORKDIR /app + +# No ENTRYPOINT: the run-build command supplies the whole command so the prompt can go +# in on stdin exactly as it does on the host. diff --git a/tools/stack-bench/container/binary-provenance.ts b/tools/stack-bench/container/binary-provenance.ts new file mode 100644 index 00000000000..9686ca2db4c --- /dev/null +++ b/tools/stack-bench/container/binary-provenance.ts @@ -0,0 +1,207 @@ +#!/usr/bin/env node + +import { createHash, randomBytes } from 'node:crypto'; +import { existsSync, readFileSync, renameSync, rmSync, statSync, writeFileSync } from 'node:fs'; +import { join, resolve } from 'node:path'; +import { pathToFileURL } from 'node:url'; + +import { binarySourceIdentity, SOURCE_IDENTITY_SCHEME } + from '../src/releases/release-source.js'; +import { STACK_BENCH_RUNNER_PLATFORM } from '../src/runtime/runner-environment.js'; + +export const RUST_BUILDER_IMAGE = + 'rust:1.93-slim-bookworm@sha256:8f8609d448e821fbc0e44241bc5ca4ce49663cc6306ff1a17f655a0e2a7cd084'; +export const BINARY_NAMES = Object.freeze(['spacetimedb-cli', 'spacetimedb-standalone']); +const PROVENANCE_NAME = 'spacetimedb-binaries.json'; + +interface BinarySourceIdentity { + identityScheme: typeof SOURCE_IDENTITY_SCHEME; + revision: string; + sha256: string; + files: number; +} + +interface BinaryRecord { + sha256: string; + size: number; +} + +interface BinaryProvenance { + schemaVersion: 2; + platform: typeof STACK_BENCH_RUNNER_PLATFORM; + builderImage: string; + source: BinarySourceIdentity; + binaries: Record; +} + +function sha256File(path: string): string { + return createHash('sha256').update(readFileSync(path)).digest('hex'); +} + +function binaryPath(stackBenchRoot: string, name: string): string { + return join(stackBenchRoot, 'container', 'bin', name); +} + +function provenancePath(stackBenchRoot: string): string { + return join(stackBenchRoot, 'container', PROVENANCE_NAME); +} + +function assertSha256(value: unknown, label: string): asserts value is string { + if (typeof value !== 'string' || !/^[a-f0-9]{64}$/.test(value)) { + throw new Error(`${label} must be a SHA-256 digest`); + } +} + +function inspectBinary(path: string, name: string): BinaryRecord { + if (!existsSync(path)) { + throw new Error(`${name} is absent; run tools/stack-bench/container/build-linux-cli.sh`); + } + const stat = statSync(path); + if (!stat.isFile() || stat.size < 4) throw new Error(`${name} is not a non-empty file`); + const magic = readFileSync(path).subarray(0, 4); + if (!magic.equals(Buffer.from([0x7f, 0x45, 0x4c, 0x46]))) { + throw new Error(`${name} is not a Linux ELF binary`); + } + return { sha256: sha256File(path), size: stat.size }; +} + +export function createBinaryProvenance(stackBenchRoot: string, + source: BinarySourceIdentity): BinaryProvenance { + if (source?.identityScheme !== SOURCE_IDENTITY_SCHEME) { + throw new Error('binary source identity scheme is unsupported'); + } + assertSha256(source?.sha256, 'binary source identity'); + if (!/^[a-f0-9]{40}(?:[a-f0-9]{24})?$/.test(source?.revision ?? '')) { + throw new Error('binary source revision must be an exact commit id'); + } + if (!Number.isSafeInteger(source?.files) || source.files < 1) { + throw new Error('binary source file count must be a positive integer'); + } + const binaries: Record = {}; + for (const name of BINARY_NAMES) binaries[name] = inspectBinary(binaryPath(stackBenchRoot, name), name); + return { + schemaVersion: 2, + platform: STACK_BENCH_RUNNER_PLATFORM, + builderImage: RUST_BUILDER_IMAGE, + source: { identityScheme: source.identityScheme, + revision: source.revision, sha256: source.sha256, files: source.files }, + binaries, + }; +} + +export function assertBinarySourceUnchanged(before: BinarySourceIdentity, + after: BinarySourceIdentity): void { + if (before?.identityScheme !== after?.identityScheme + || before?.revision !== after?.revision || before?.sha256 !== after?.sha256 + || before?.files !== after?.files) { + throw new Error('binary source changed during the build'); + } +} + +function readProvenance(stackBenchRoot: string): BinaryProvenance { + const path = provenancePath(stackBenchRoot); + if (!existsSync(path)) { + throw new Error(`${PROVENANCE_NAME} is absent; run tools/stack-bench/container/build-linux-cli.sh`); + } + let manifest: BinaryProvenance & { status?: string }; + try { manifest = JSON.parse(readFileSync(path, 'utf8')); } + catch (error) { + throw new Error(`${PROVENANCE_NAME} is not valid JSON: ${error instanceof Error + ? error.message : String(error)}`); + } + if (manifest.status === 'unbuilt') { + throw new Error(`${PROVENANCE_NAME} has no verified binaries; run tools/stack-bench/container/build-linux-cli.sh`); + } + return manifest; +} + +export function verifyBinaryProvenance(stackBenchRoot: string, + { sourceSha256 }: { sourceSha256: string }): BinaryProvenance { + assertSha256(sourceSha256, 'expected binary source identity'); + const manifest = readProvenance(stackBenchRoot); + if (manifest.schemaVersion !== 2) throw new Error('unsupported binary provenance schema'); + if (manifest.platform !== STACK_BENCH_RUNNER_PLATFORM) { + throw new Error(`binary provenance platform must be ${STACK_BENCH_RUNNER_PLATFORM}`); + } + if (manifest.builderImage !== RUST_BUILDER_IMAGE) { + throw new Error('binary provenance does not use the pinned Rust builder image'); + } + assertSha256(manifest.source?.sha256, 'recorded binary source identity'); + if (manifest.source.identityScheme !== SOURCE_IDENTITY_SCHEME) { + throw new Error('recorded binary source identity scheme is unsupported'); + } + if (manifest.source.sha256 !== sourceSha256) { + throw new Error('SpacetimeDB binaries do not match the selected release source'); + } + if (!/^[a-f0-9]{40}(?:[a-f0-9]{24})?$/.test(manifest.source?.revision ?? '')) { + throw new Error('recorded binary source revision is invalid'); + } + if (!Number.isSafeInteger(manifest.source?.files) || manifest.source.files < 1) { + throw new Error('recorded binary source file count is invalid'); + } + for (const name of BINARY_NAMES) { + const expected = manifest.binaries?.[name]; + assertSha256(expected?.sha256, `${name} recorded checksum`); + if (!Number.isSafeInteger(expected.size) || expected.size < 4) { + throw new Error(`${name} recorded size is invalid`); + } + const actual = inspectBinary(binaryPath(stackBenchRoot, name), name); + if (actual.size !== expected.size) throw new Error(`${name} size does not match provenance`); + if (actual.sha256 !== expected.sha256) throw new Error(`${name} checksum does not match provenance`); + } + return manifest; +} + +function option(args: string[], name: string): string { + const index = args.indexOf(name); + const value = index === -1 ? undefined : args[index + 1]; + if (!value) throw new Error(`${name} is required`); + return value; +} + +function main(): void { + const [command, ...args] = process.argv.slice(2); + if (command === 'source') { + const repo = resolve(option(args, '--repo')); + console.log(JSON.stringify(binarySourceIdentity(repo), null, 2)); + return; + } + if (command === 'record') { + const repo = resolve(option(args, '--repo')); + const stackBenchRoot = join(repo, 'tools', 'stack-bench'); + const source = JSON.parse(readFileSync(resolve(option(args, '--source-file')), 'utf8')); + const current = binarySourceIdentity(repo); + assertBinarySourceUnchanged(source, current); + const manifest = createBinaryProvenance(stackBenchRoot, source); + const path = provenancePath(stackBenchRoot); + const temporary = `${path}.${process.pid}.${randomBytes(8).toString('hex')}.tmp`; + writeFileSync(temporary, `${JSON.stringify(manifest, null, 2)}\n`, { flag: 'wx' }); + try { renameSync(temporary, path); } + catch (error) { rmSync(temporary, { force: true }); throw error; } + console.log(`recorded ${path}`); + return; + } + if (command === 'record-snapshot') { + // The Docker source stage records this identity before compiling the same + // immutable Git archive. This path needs no host-built binary or Git metadata. + const root = resolve(option(args, '--root')); + const source = JSON.parse(readFileSync(resolve(option(args, '--source-file')), 'utf8')); + writeFileSync(provenancePath(root), `${JSON.stringify(createBinaryProvenance(root, source), null, 2)}\n`); + return; + } + if (command === 'verify') { + const stackBenchRoot = resolve(option(args, '--root')); + verifyBinaryProvenance(stackBenchRoot, { sourceSha256: option(args, '--source-sha256') }); + console.log('verified SpacetimeDB CLI and standalone binary provenance'); + return; + } + throw new Error('Usage: binary-provenance source --repo PATH | record --repo PATH --source-file PATH | verify --root PATH --source-sha256 SHA256'); +} + +if (process.argv[1] && pathToFileURL(resolve(process.argv[1])).href === import.meta.url) { + try { main(); } + catch (error) { + console.error(`binary provenance failed: ${error instanceof Error ? error.message : String(error)}`); + process.exit(1); + } +} diff --git a/tools/stack-bench/container/broker-protocols.ts b/tools/stack-bench/container/broker-protocols.ts new file mode 100644 index 00000000000..9cab18b3a02 --- /dev/null +++ b/tools/stack-bench/container/broker-protocols.ts @@ -0,0 +1,285 @@ +import type { IncomingMessage, OutgoingHttpHeaders } from 'node:http'; +import { brotliDecompressSync, gunzipSync, inflateSync } from 'node:zlib'; +import { createParser } from 'eventsource-parser'; +import type { BrokerConfig } from './credential-broker-accounting.js'; + +const MAX_REQUEST_BYTES = 32 * 1024 * 1024; +type JsonRecord = Record; +function isRecord(value: unknown): value is JsonRecord { + return value !== null && typeof value === 'object' && !Array.isArray(value); +} +function isNumber(value: unknown): value is number { return typeof value === 'number'; } +function fail(message: string): never { throw new Error(`credential broker: ${message}`); } + +function upstreamHeaders(request: IncomingMessage, config: BrokerConfig): OutgoingHttpHeaders { + const headers: OutgoingHttpHeaders = { ...request.headers }; + delete headers.host; + // Request identity encoding so accounting and the client read the same bytes. + delete headers['accept-encoding']; + delete headers.authorization; + delete headers['proxy-authorization']; + delete headers['x-api-key']; + if (config.mode === 'api-key') headers['x-api-key'] = config.credential; + else headers.authorization = `Bearer ${config.credential}`; + return headers; +} + +function parseProviderRequest(body: Buffer, path: string, config: BrokerConfig): JsonRecord { + let payload: unknown; + try { payload = JSON.parse(body.toString('utf8')); } + catch { fail('request body must be valid JSON'); } + if (!isRecord(payload)) { + fail('request body must be an object'); + } + if (payload.model !== config.model) fail('request model does not match the selected model'); + if (path === '/v1/messages' + && (!isNumber(payload.max_tokens) || !Number.isInteger(payload.max_tokens) || payload.max_tokens < 1 + || payload.max_tokens > config.maxOutputTokens)) { + fail(`max_tokens must be from 1 through ${config.maxOutputTokens}`); + } + return payload; +} + +function decodedResponseBody(body: Buffer, contentEncoding: string | string[] | undefined): Buffer { + const encodings = String(contentEncoding ?? '') + .split(',').map(value => value.trim().toLowerCase()).filter(Boolean); + let decoded = body; + for (const encoding of encodings.reverse()) { + if (encoding === 'identity') continue; + const options = { maxOutputLength: MAX_REQUEST_BYTES }; + if (encoding === 'gzip' || encoding === 'x-gzip') decoded = gunzipSync(decoded, options); + else if (encoding === 'deflate') decoded = inflateSync(decoded, options); + else if (encoding === 'br') decoded = brotliDecompressSync(decoded, options); + else throw new Error(`unsupported response encoding ${encoding}`); + } + return decoded; +} + +function responseUsage(body: Buffer, contentEncoding: string | string[] | undefined = undefined): JsonRecord | null { + const values: JsonRecord[] = []; + const add = (value: unknown): void => { + if (!isRecord(value)) return; + if (isRecord(value.usage)) values.push(value.usage); + if (isRecord(value.message) && isRecord(value.message.usage)) values.push(value.message.usage); + }; + let text: string; + try { text = decodedResponseBody(body, contentEncoding).toString('utf8'); } + catch { return null; } + try { + add(JSON.parse(text)); + } catch { + let sawError = false; + let sawFinalUsage = false; + let sawMessageStop = false; + let parseError = false; + const parser = createParser({ + maxBufferSize: MAX_REQUEST_BYTES, + onError: () => { parseError = true; }, + onEvent: ({ data }) => { + if (!data || data === '[DONE]') return; + try { + const event = JSON.parse(data); + if (isRecord(event) && event.type === 'error') sawError = true; + if (isRecord(event) && event.type === 'message_delta' && isRecord(event.usage)) { + sawFinalUsage = true; + } + if (isRecord(event) && event.type === 'message_stop') sawMessageStop = true; + add(event); + } catch { /* Ignore non-JSON event data. */ } + }, + }); + try { parser.feed(`${text}\n\n`); } + catch { parseError = true; } + if (parseError || sawError || !sawFinalUsage || !sawMessageStop) return null; + } + if (values.length === 0) return null; + const number = (field: string): number => Math.max(0, ...values.map(value => Number(value[field]) || 0)); + const cacheWrite = (field: string): number => Math.max(0, ...values.map(value => + isRecord(value.cache_creation) ? Number(value.cache_creation[field]) || 0 : 0)); + const cacheWrite5m = cacheWrite('ephemeral_5m_input_tokens'); + const cacheWrite1h = cacheWrite('ephemeral_1h_input_tokens'); + const flatCacheWrite = number('cache_creation_input_tokens'); + return { + input_tokens: number('input_tokens'), + output_tokens: number('output_tokens'), + cache_read_input_tokens: number('cache_read_input_tokens'), + cache_creation: { + ephemeral_5m_input_tokens: cacheWrite5m + cacheWrite1h > 0 ? cacheWrite5m : flatCacheWrite, + ephemeral_1h_input_tokens: cacheWrite1h, + }, + }; +} + + +interface BrokerProtocol { + hostname: string; + allowedPaths: Set; + upstreamPath(path: string): string; + billable(path: string): boolean; + headers(request: IncomingMessage): OutgoingHttpHeaders; + parseRequest(body: Buffer, path: string): JsonRecord; + inputTokenAdjustment?(payload: JsonRecord): number; + outputLimit(payload: JsonRecord): number; + responseUsage(body: Buffer, encoding?: string | string[]): JsonRecord | null; +} + +function responsesUsage(body: Buffer, encoding?: string | string[], config?: BrokerConfig): JsonRecord | null { + let response: JsonRecord | null = null; + let failed = false; + let metadata: JsonRecord | null = null; + const accept = (value: unknown): void => { + if (!isRecord(value)) return; + if (isRecord(value.openrouter_metadata)) metadata = value.openrouter_metadata; + if (value.type === 'error' || value.type === 'response.failed') failed = true; + if ((value.type === 'response.completed' || value.type === 'response.incomplete' + || (config?.provider === 'openrouter' && value.type === 'response.done')) && isRecord(value.response)) { + response = value.response; + } else if (value.object === 'response' && (value.status === 'completed' || value.status === 'incomplete')) { + response = value; + } + }; + try { + const text = decodedResponseBody(body, encoding).toString('utf8'); + try { accept(JSON.parse(text)); } + catch { + const parser = createParser({ maxBufferSize: MAX_REQUEST_BYTES, + onError: () => { failed = true; }, + onEvent: ({ data }) => { + if (data === '[DONE]') return; + try { accept(JSON.parse(data)); } catch { failed = true; } + }, + }); + parser.feed(`${text}\n\n`); + } + } catch { return null; } + const usage = (response as JsonRecord | null)?.usage; + if (failed || !isRecord(usage)) return null; + const input = usage.input_tokens; + const output = usage.output_tokens; + const cached = isRecord(usage.input_tokens_details) ? usage.input_tokens_details.cached_tokens : 0; + if (![input, output, cached].every(value => typeof value === 'number' && Number.isSafeInteger(value) && value >= 0) + || (cached as number) > (input as number)) return null; + const normalized = { input_tokens: (input as number) - (cached as number), output_tokens: output, + cache_read_input_tokens: cached, cache_creation_input_tokens: 0 }; + if (config?.provider !== 'openrouter') return normalized; + const final = response as JsonRecord | null; + const route = (final?.openrouter_metadata ?? metadata) as JsonRecord | null; + const selected = isRecord(route?.endpoints) && Array.isArray(route.endpoints.available) + ? route.endpoints.available.filter(endpoint => isRecord(endpoint) && endpoint.selected === true) : []; + if (typeof usage.cost !== 'number' || !Number.isFinite(usage.cost) || usage.cost < 0 + || final?.model !== config.model || !route || route.requested !== config.model + || route.strategy !== 'direct' || route.is_byok !== false || route.attempt !== 1 + || (route.pipeline !== undefined && (!Array.isArray(route.pipeline) || route.pipeline.length !== 0)) + || selected.length !== 1 || !isRecord(selected[0]) || selected[0].model !== config.model + || typeof selected[0].provider !== 'string' || !selected[0].provider || selected[0].provider.length > 128) return null; + return { ...normalized, provider_reported_cost_usd: usage.cost, upstream_provider: selected[0].provider }; +} + + +function hasUnpricedInput(value: unknown): boolean { + if (Array.isArray(value)) return value.some(hasUnpricedInput); + if (!isRecord(value)) return false; + if (['input_file', 'item_reference'].includes(String(value.type))) return true; + return Object.values(value).some(hasUnpricedInput); +} + +// Only inline images have bounded input here. Provider receipts price actual tokens. +export function imageTokenAdjustment(value: unknown, model: string): number { + if (Array.isArray(value)) return value.reduce((sum, item) => sum + imageTokenAdjustment(item, model), 0); + if (!isRecord(value)) return 0; + if (value.type === 'input_image') { + if (!['gpt-6-astra', 'gpt-5.6-sol', 'gpt-5.6-terra', 'gpt-5.6-luna', 'gpt-5.4', 'gpt-5.4-2026-03-05'].includes(model) + || typeof value.image_url !== 'string' + || !/^data:image\/(png|jpeg|webp|gif);base64,[A-Za-z0-9+/]+={0,2}$/.test(value.image_url) + || value.file_id !== undefined) fail('image input requires inline data and a verified token bound'); + // OpenAI vision: 30,000 patches maximum x 1.2 tokens, plus rounding. + // https://developers.openai.com/api/docs/guides/images-vision + // Replace base64 text bytes rather than charging for both representations. + return 36_001 - Buffer.byteLength(value.image_url, 'utf8'); + } + return Object.values(value).reduce((sum, item) => sum + imageTokenAdjustment(item, model), 0); +} + +export function brokerProtocol(config: BrokerConfig): BrokerProtocol { + if (!config.provider || config.provider === 'anthropic') return { + hostname: 'api.anthropic.com', + allowedPaths: new Set(['/v1/messages', '/v1/messages/count_tokens']), + upstreamPath: path => path, + billable: path => path === '/v1/messages', + headers: request => upstreamHeaders(request, config), + parseRequest: (body, path) => parseProviderRequest(body, path, config), + outputLimit: payload => payload.max_tokens as number, + responseUsage, + }; + const router = config.provider === 'openrouter'; + if (router && (!/^[a-z0-9._-]+\/[a-zA-Z0-9._-]+$/.test(config.model) + || config.model.startsWith('openrouter/') || /(?:^|[-/])latest$/.test(config.model))) { + fail('OpenRouter requires one explicit model without routing variants'); + } + const account = config.mode === 'subscription-token'; + if (account && !config.accountId) fail('OpenAI account identity is required'); + // Account Responses does not promise max_output_tokens. Use a documented model + // bound, never assume an unknown model shares it. API requests enforce the cap. + const accountOutputLimits: Record = { 'gpt-5.3-codex': 128_000, 'gpt-5.4': 128_000, 'gpt-5.4-2026-03-05': 128_000, + 'gpt-5.6-sol': 128_000, 'gpt-6-astra': 128_000 }; + const outputLimit = account + ? Object.hasOwn(accountOutputLimits, config.model) ? accountOutputLimits[config.model] : undefined + : config.maxOutputTokens; + if (!outputLimit) fail('OpenAI account model has no verified output-token bound'); + return { + hostname: router ? 'openrouter.ai' : account ? 'chatgpt.com' : 'api.openai.com', + allowedPaths: new Set(['/v1/responses']), + upstreamPath: () => router ? '/api/v1/responses' : account ? '/backend-api/codex/responses' : '/v1/responses', + billable: () => true, + headers: request => { + // OpenRouter routing/auth headers are trusted configuration, not agent input. + const headers = router ? { 'content-type': 'application/json', accept: 'text/event-stream', + 'x-openrouter-metadata': 'enabled' } as OutgoingHttpHeaders : upstreamHeaders(request, config); + delete headers['x-api-key']; + for (const name of ['chatgpt-account-id', 'openai-organization', 'openai-project']) delete headers[name]; + headers.authorization = `Bearer ${config.credential}`; + if (account) headers['chatgpt-account-id'] = config.accountId; + return headers; + }, + parseRequest: body => { + const payload = JSON.parse(body.toString('utf8')); + if (!isRecord(payload) || payload.model !== config.model) fail('request model does not match'); + imageTokenAdjustment(payload.input, config.model); + // Token-only receipts cannot price hosted tools or hidden server-side input. + if (payload.prompt || payload.previous_response_id || payload.conversation || hasUnpricedInput(payload.input) + || payload.image_config !== undefined || payload.audio !== undefined + || (payload.modalities !== undefined && (!Array.isArray(payload.modalities) + || payload.modalities.some(modality => modality !== 'text'))) + || (payload.truncation !== undefined && payload.truncation !== 'disabled') + || payload.background === true + || (payload.service_tier !== undefined && payload.service_tier !== 'default' && payload.service_tier !== 'auto') + || (payload.tools !== undefined && (!Array.isArray(payload.tools) + || payload.tools.some(tool => !isRecord(tool) || !['function', 'custom'].includes(String(tool.type)))))) { + fail('request requires unsupported pricing or server-side state'); + } + if (router && ['provider', 'models', 'route', 'plugins', 'transforms', 'preset', 'user', 'session_id', 'trace', 'debug'].some(key => key in payload)) { + fail('OpenRouter routing and transforms are owned by the broker'); + } + const requested = payload.max_output_tokens; + if (requested !== undefined && (!Number.isSafeInteger(requested) || (requested as number) < 1 + || (requested as number) > outputLimit)) fail('invalid max_output_tokens'); + if (!account) { + payload.max_output_tokens = requested ?? outputLimit; + payload.service_tier = 'default'; + } + if (router) { + const rates = config.pricingRates!; + payload.provider = { only: [config.providerRoute], order: [config.providerRoute], + allow_fallbacks: false, require_parameters: true, + max_price: { prompt: rates.input, completion: rates.output, request: 0 } }; + payload.plugins = []; + payload.transforms = []; + payload.store = false; + } + return payload; + }, + inputTokenAdjustment: payload => imageTokenAdjustment(payload.input, config.model), + outputLimit: payload => account ? outputLimit : payload.max_output_tokens as number, + responseUsage: (body, encoding) => responsesUsage(body, encoding, config), + }; +} diff --git a/tools/stack-bench/container/browser-pipe.ts b/tools/stack-bench/container/browser-pipe.ts new file mode 100644 index 00000000000..15bc88d56f5 --- /dev/null +++ b/tools/stack-bench/container/browser-pipe.ts @@ -0,0 +1,63 @@ +#!/usr/bin/env node + +import { spawn } from 'node:child_process'; +import { Socket } from 'node:net'; +import { resolve } from 'node:path'; +import { pathToFileURL } from 'node:url'; +import { chromium } from 'playwright'; +import type { LaunchOptions } from 'playwright'; +import { compiledEntrypoint } from '../src/package-root.js'; +import { readBackendLease } from '../src/runtime/backend-lease.js'; + +function browserContainer(): string | null { + const path = process.env.STACK_BENCH_LEASE; + if (!path) { + if (process.env.STACK_BENCH_APPLIANCE === '1') throw new Error('browser requires a private attempt lease'); + return null; + } + const token = process.env.STACK_BENCH_LEASE_TOKEN; + if (!token) throw new Error('browser requires the attempt ownership token'); + const lease = readBackendLease(path, { token }); + if (lease.backend === 'stub') return null; + const container = lease.resources.browserContainer; + if (!container?.owned || container.running === false || !/^[a-f0-9]{64}$/.test(container.id)) { + throw new Error('browser requires the exact running attempt browser container'); + } + return container.id; +} + +export function attemptBrowserLaunchOptions(): LaunchOptions { + return browserContainer() ? { + executablePath: compiledEntrypoint('container', 'browser-pipe.js'), + // The owned browser has private shared memory; do not fill /tmp with IPC buffers. + ignoreDefaultArgs: ['--disable-dev-shm-usage'], + } : {}; +} + +// Playwright uses fd 3/4. Docker carries these bytes over stdin/stdout, so no +// browser control socket is reachable from the generated app's network. +function main(): void { + const id = browserContainer(); + if (!id) throw new Error('browser pipe requires an isolated attempt'); + const child = spawn('docker', ['exec', '-i', id, 'sh', '-c', + 'exec 3<&0 4>&1 1>&2; exec "$@"', 'sh', chromium.executablePath(), ...process.argv.slice(2)], + { stdio: ['pipe', 'pipe', 'inherit'] }); + const input = new Socket({ fd: 3, readable: true, writable: false }); + const output = new Socket({ fd: 4, readable: false, writable: true }); + input.pipe(child.stdin); + child.stdout.pipe(output); + const close = () => { input.destroy(); child.stdin.end(); }; + process.on('SIGTERM', close); + process.on('SIGINT', close); + child.stdin.on('error', error => { + if ('code' in error && error.code === 'EPIPE') close(); + else throw error; + }); + child.on('error', error => { console.error(error.message); process.exit(1); }); + child.on('exit', () => { input.destroy(); child.stdin.destroy(); }); + // fd 3 can still have a pending read while Playwright waits for this process + // to exit. Docker's close event means all browser output has been forwarded. + child.on('close', code => { process.exit(code ?? 1); }); +} + +if (process.argv[1] && pathToFileURL(resolve(process.argv[1])).href === import.meta.url) main(); diff --git a/tools/stack-bench/container/browser-tools/package-lock.json b/tools/stack-bench/container/browser-tools/package-lock.json new file mode 100644 index 00000000000..cd5ab8d8f7e --- /dev/null +++ b/tools/stack-bench/container/browser-tools/package-lock.json @@ -0,0 +1,328 @@ +{ + "name": "stack-bench-browser-tools", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "stack-bench-browser-tools", + "dependencies": { + "puppeteer-core": "25.10.0" + } + }, + "node_modules/@puppeteer/browsers": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-3.2.2.tgz", + "integrity": "sha512-q2BU4YfO9h/Wt7IcWPcggpOOqLk2Tbs1hDwolvKZrweRjy751OJBKMN9zO5bfD0pzU7X/tvKw/exQds4pM/LOg==", + "license": "Apache-2.0", + "dependencies": { + "modern-tar": "^0.8.4", + "yargs": "^18.0.0" + }, + "bin": { + "browsers": "lib/main-cli.js" + }, + "engines": { + "node": ">=22.12.0" + }, + "peerDependencies": { + "proxy-agent": ">=8.0.1", + "yauzl": "^2.10.0 || ^3.4.0" + }, + "peerDependenciesMeta": { + "proxy-agent": { + "optional": true + }, + "yauzl": { + "optional": true + } + } + }, + "node_modules/ansi-regex": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.3.0.tgz", + "integrity": "sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/chromium-bidi": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-17.0.2.tgz", + "integrity": "sha512-5v9GQFhTktFvotn/OFNJBmKLKRAb6n9r0bVCwf7sHgWc3/JryK0bj1nn93L3pHFrfgcsu6Be6EWsDi+1XHTGDg==", + "license": "Apache-2.0", + "dependencies": { + "mitt": "^3.0.1", + "zod": "^3.24.1" + }, + "engines": { + "node": ">=20.19.0 <22.0.0 || >=22.12.0" + }, + "peerDependencies": { + "devtools-protocol": "*" + } + }, + "node_modules/cliui": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz", + "integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==", + "license": "ISC", + "dependencies": { + "string-width": "^7.2.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/cliui/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/devtools-protocol": { + "version": "0.0.1666840", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1666840.tgz", + "integrity": "sha512-gCcO42XCHKEs7Ag0S7aGYsnJ7hlgrO3qderYqeiY0Eqk+0GFfuvT13IA0hHreJTa2KCdDVyGMeOhdMNmrrTjVg==", + "license": "BSD-3-Clause" + }, + "node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "license": "MIT" + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-east-asian-width": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.6.0.tgz", + "integrity": "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mitt": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", + "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", + "license": "MIT" + }, + "node_modules/modern-tar": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/modern-tar/-/modern-tar-0.8.5.tgz", + "integrity": "sha512-snEhs+6G5Tjd4I7tLCDOaoln2RgE0bD19RzEKgvgK2hZ5VKy3MpLhLTZ2fWpXSTg4K2cyPwp+VHATFJhxfnOeA==", + "license": "MIT", + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/puppeteer-core": { + "version": "25.10.0", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-25.10.0.tgz", + "integrity": "sha512-Hy5eMQshOEMil4JUUx03h5pw1HYkYCso1RG/gcpPlFSd4cYPOcopxcXEAxpLPOkOPJb9LIJtwxuj66bSdvknFg==", + "license": "Apache-2.0", + "dependencies": { + "@puppeteer/browsers": "3.2.2", + "chromium-bidi": "17.0.2", + "devtools-protocol": "0.0.1666840", + "typed-query-selector": "^2.12.2", + "webdriver-bidi-protocol": "0.4.3", + "ws": "^8.21.3" + }, + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/string-width": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.2.2.tgz", + "integrity": "sha512-GaPUh5gfdrYzqeVNZvUfT23vYYxXzKYidUcnMtJg/3rxRV63EFZy3k6xfKlmfeJD0176lnUV/Usr3XcwSvFzpg==", + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.5.0", + "strip-ansi": "^7.1.2" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/typed-query-selector": { + "version": "2.12.2", + "resolved": "https://registry.npmjs.org/typed-query-selector/-/typed-query-selector-2.12.2.tgz", + "integrity": "sha512-EOPFbyIub4ngnEdqi2yOcNeDLaX/0jcE1JoAXQDDMIthap7FoN795lc/SHfIq2d416VufXpM8z/lD+WRm2gfOQ==", + "license": "MIT" + }, + "node_modules/webdriver-bidi-protocol": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/webdriver-bidi-protocol/-/webdriver-bidi-protocol-0.4.3.tgz", + "integrity": "sha512-uuN0goWfxP22B7J/uAgBpOYNPttC+XVseYE+rSY5+rQ+YBeVz/VORw8WbmLVcqW78zNg5A4qnjNXYUWR3il2ig==", + "license": "Apache-2.0" + }, + "node_modules/wrap-ansi": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ws": { + "version": "8.21.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.3.tgz", + "integrity": "sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs": { + "version": "18.1.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.1.0.tgz", + "integrity": "sha512-2rAgRKu54VsHkqI0/tYkmluGXHD4KW7yZoycuqDQ15QOTnc2VVfy0nN/1eMhnQLO00A+dwtK20xuCnc1YGeUyg==", + "license": "MIT", + "dependencies": { + "cliui": "^9.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "string-width": "^8.2.1", + "y18n": "^5.0.5", + "yargs-parser": "^22.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=23" + } + }, + "node_modules/yargs-parser": { + "version": "22.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz", + "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==", + "license": "ISC", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=23" + } + }, + "node_modules/zod": { + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + } + } +} diff --git a/tools/stack-bench/container/browser-tools/package.json b/tools/stack-bench/container/browser-tools/package.json new file mode 100644 index 00000000000..5d7eeecaa9c --- /dev/null +++ b/tools/stack-bench/container/browser-tools/package.json @@ -0,0 +1 @@ +{"name":"stack-bench-browser-tools","private":true,"dependencies":{"puppeteer-core":"25.10.0"}} diff --git a/tools/stack-bench/container/build-container-inspection.ts b/tools/stack-bench/container/build-container-inspection.ts new file mode 100644 index 00000000000..22605d0a3f5 --- /dev/null +++ b/tools/stack-bench/container/build-container-inspection.ts @@ -0,0 +1,228 @@ +import { spawnSync } from 'node:child_process'; +import type { SpawnSyncOptionsWithStringEncoding, SpawnSyncReturns } from 'node:child_process'; +import { resolve } from 'node:path'; + +import { LEGACY_SUBSCRIPTION_TOKEN_TARGET } from './container-auth.js'; +import type { ContainerMount } from '../src/runtime/container-mount.js'; +import { redactCredentials } from '../src/evidence/diagnostic-sanitizer.js'; + +type InspectedMount = { + type: string; + source: string; + name: string | null; + destination: string; + readOnly: boolean; +}; + +export type InspectedBuildContainer = { + id: string; + image: string; + running: boolean; + networkMode: string | null; + readonlyRootfs: boolean; + tmpfs: Record; + capAdd: string[]; + capDrop: string[]; + securityOpt: string[]; + pidsLimit: number | null; + nanoCpus: number | null; + memoryBytes: number | null; + memorySwapBytes: number | null; + mounts: InspectedMount[]; + unsafeCredentialExposure: boolean; +}; + +type DockerExecute = (command: string, args: readonly string[], + options: SpawnSyncOptionsWithStringEncoding) => SpawnSyncReturns; + +type JsonRecord = Record; + +function isRecord(value: unknown): value is JsonRecord { + return value !== null && typeof value === 'object' && !Array.isArray(value); +} + +function stringArray(value: unknown): string[] { + return Array.isArray(value) ? value.filter((item): item is string => typeof item === 'string') : []; +} + +function numberOrNull(value: unknown): number | null { + return typeof value === 'number' ? value : null; +} + +function dockerDetail(result: SpawnSyncReturns): string { + return String(result.stderr || result.stdout || result.error?.message || `exit ${result.status}`).trim(); +} + +export function waitForBuildContainerReady(id: string, readyFile: string, description: string, { + env = process.env, + execute = spawnSync as DockerExecute, +}: { env?: NodeJS.ProcessEnv; execute?: DockerExecute } = {}): void { + const options = { encoding: 'utf8' as const, env, timeout: 10_000 }; + try { + const deadline = Date.now() + 90_000; + while (Date.now() < deadline) { + const probe = execute('docker', ['exec', id, 'test', '-f', readyFile], options); + if (probe.status === 0) return; + const inspection = execute('docker', ['inspect', '--format', '{{json .State}}', id], options); + if (inspection.status !== 0) throw new Error(`cannot inspect build container ${id}: ${dockerDetail(inspection)}`); + const state = JSON.parse(inspection.stdout) as { Status: string; ExitCode: number; OOMKilled: boolean }; + if (state.Status === 'exited' || state.Status === 'dead') { + throw new Error(`build container ${id} ${state.Status} before ${description}; ` + + `exit code ${state.ExitCode}; OOMKilled=${state.OOMKilled}`); + } + Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 500); + } + throw new Error(`timed out waiting for ${description}`); + } catch (error) { + const logs = execute('docker', ['logs', '--tail', '100', id], options); + throw new Error(redactCredentials(`${error instanceof Error ? error.message : String(error)}\n` + + `${logs.stdout || ''}${logs.stderr || ''}`)); + } +} + +export function parseCgroupResources(value: string) { + const count = (name: string, key?: string): number | null => { + const section = (value.split(`[${name}]`)[1]?.split('[')[0] ?? '').replaceAll('\r', ''); + const match = section.match(new RegExp(key ? `^${key} (\\d+)$` : '^(\\d+)$', 'm')); + if (!match) return null; + const parsed = Number(match[1]); + return Number.isSafeInteger(parsed) ? parsed : null; + }; + return { + buildContainerMemory: { + currentBytes: count('memory.current'), + peakBytes: count('memory.peak'), + limitBytes: count('memory.max'), + oomEvents: count('memory.events', 'oom'), + oomKillEvents: count('memory.events', 'oom_kill'), + }, + buildContainerPids: { + current: count('pids.current'), + peak: count('pids.peak'), + limit: count('pids.max'), + limitEvents: count('pids.events', 'max'), + }, + }; +} + +export function inspectBuildContainer(name: string, { + env = process.env, + timeoutMs = 120_000, + execute = spawnSync as DockerExecute, +}: { env?: NodeJS.ProcessEnv; timeoutMs?: number; execute?: DockerExecute } = {}): InspectedBuildContainer | null { + const result = execute('docker', ['inspect', name], { encoding: 'utf8', env, timeout: timeoutMs }); + if (result.status !== 0) { + const detail = dockerDetail(result); + if (/no such (?:object|container)/i.test(detail)) return null; + throw new Error(`cannot inspect build container ${name}: ${detail}`); + } + + let parsed: unknown; + try { parsed = JSON.parse(result.stdout); } + catch (error) { + throw new Error(`Docker returned invalid inspection JSON for ${name}: ${error instanceof Error + ? error.message : String(error)}`); + } + if (!Array.isArray(parsed) || !isRecord(parsed[0])) { + throw new Error(`Docker returned an invalid container inspection for ${name}`); + } + + const inspected = parsed[0]; + const mounts = Array.isArray(inspected.Mounts) ? inspected.Mounts.filter(isRecord) : []; + const config = isRecord(inspected.Config) ? inspected.Config : {}; + const hostConfig = isRecord(inspected.HostConfig) ? inspected.HostConfig : {}; + const state = isRecord(inspected.State) ? inspected.State : {}; + const sensitiveTargets = new Set([LEGACY_SUBSCRIPTION_TOKEN_TARGET, '/root/.claude/.credentials.json', + '/root/.codex/auth.json', '/home/developer/.codex/auth.json']); + const capabilities = (values: unknown): string[] => stringArray(values).map(value => value.replace(/^CAP_/, '')); + const tmpfs = isRecord(hostConfig.Tmpfs) + ? Object.fromEntries(Object.entries(hostConfig.Tmpfs) + .filter((entry): entry is [string, string] => typeof entry[1] === 'string')) : {}; + + return { + id: String(inspected.Id), + image: String(inspected.Image), + running: state.Running === true, + networkMode: typeof hostConfig.NetworkMode === 'string' ? hostConfig.NetworkMode : null, + readonlyRootfs: hostConfig.ReadonlyRootfs === true, + tmpfs, + capAdd: capabilities(hostConfig.CapAdd), + capDrop: capabilities(hostConfig.CapDrop), + securityOpt: stringArray(hostConfig.SecurityOpt).map(option => option.replace(/:true$/, '')), + pidsLimit: numberOrNull(hostConfig.PidsLimit), + nanoCpus: numberOrNull(hostConfig.NanoCpus), + memoryBytes: numberOrNull(hostConfig.Memory), + memorySwapBytes: numberOrNull(hostConfig.MemorySwap), + mounts: mounts.map(mount => ({ + type: String(mount.Type), + source: String(mount.Source), + name: typeof mount.Name === 'string' ? mount.Name : null, + destination: String(mount.Destination), + readOnly: mount.RW !== true, + })), + unsafeCredentialExposure: mounts.some(mount => sensitiveTargets.has(String(mount.Destination))) + || stringArray(config.Env).some(value => /^(?:ANTHROPIC_API_KEY|CLAUDE_CODE_OAUTH_TOKEN|OPENAI_API_KEY|OPENROUTER_API_KEY|CODEX_AUTH_FILE)=/.test(value)), + }; +} + +export function sameHostPath(left: string, right: string, + platform: NodeJS.Platform = process.platform): boolean { + const normalize = (value: string): string => resolve(value).replaceAll('\\', '/'); + const normalizedLeft = normalize(left); + const normalizedRight = normalize(right); + return platform === 'win32' + ? normalizedLeft.toLowerCase() === normalizedRight.toLowerCase() + : normalizedLeft === normalizedRight; +} + +export function parsePublishedPorts(value: string | undefined): string[] { + if (!value) return []; + const ports = value.split(',').map(port => port.trim()).filter(Boolean); + if (ports.some(port => !/^\d+$/.test(port) || Number(port) < 1 || Number(port) > 65_535)) { + throw new Error('--ports must contain integers from 1 through 65535'); + } + if (new Set(ports).size !== ports.length) throw new Error('--ports must not contain duplicates'); + return ports; +} + +export function hasRequiredBuildContainerIsolation(container: InspectedBuildContainer, { + expectedMounts, + requiredTmpfs, + requiredCapabilities, + pidsLimit, + cpuCount, + memoryBytes, + memorySwapBytes, + image, +}: { + expectedMounts: ContainerMount[]; + requiredTmpfs: Readonly>; + requiredCapabilities: readonly string[]; + pidsLimit: number; + cpuCount: number; + memoryBytes: number; + memorySwapBytes: number; + image: string; +}): boolean { + const mountsMatch = container.mounts.length === expectedMounts.length + && expectedMounts.every(expected => container.mounts.some(actual => + actual.type === (expected.kind ?? 'bind') + && actual.destination === expected.target + && actual.readOnly === expected.readOnly + && (expected.kind === 'volume' + ? actual.name === expected.source + : sameHostPath(actual.source, expected.source)))); + return container.readonlyRootfs + && Object.entries(requiredTmpfs).every(([path, options]) => container.tmpfs[path] === options) + && Object.keys(container.tmpfs).length === Object.keys(requiredTmpfs).length + && requiredCapabilities.every(capability => container.capAdd.includes(capability)) + && container.capAdd.length === requiredCapabilities.length + && container.capDrop.includes('ALL') + && container.securityOpt.includes('no-new-privileges') + && container.pidsLimit === pidsLimit + && container.nanoCpus === cpuCount * 1_000_000_000 + && container.memoryBytes === memoryBytes + && container.memorySwapBytes === memorySwapBytes + && container.image === image + && mountsMatch; +} diff --git a/tools/stack-bench/container/build-linux-cli.sh b/tools/stack-bench/container/build-linux-cli.sh new file mode 100644 index 00000000000..8ce82bb007f --- /dev/null +++ b/tools/stack-bench/container/build-linux-cli.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +# Export native binaries through the same Docker build used by the appliance. +set -euo pipefail +HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO="$(cd "$HERE/../../.." && pwd)" +MSYS_NO_PATHCONV=1 docker build --platform linux/amd64 \ + --file "$REPO/tools/stack-bench/appliance/Controller.Dockerfile" \ + --target binary-export --output "type=local,dest=$HERE" "$REPO" diff --git a/tools/stack-bench/container/claude-transcript-reader.ts b/tools/stack-bench/container/claude-transcript-reader.ts new file mode 100644 index 00000000000..604c3c3d610 --- /dev/null +++ b/tools/stack-bench/container/claude-transcript-reader.ts @@ -0,0 +1,54 @@ +import { execFileSync } from 'node:child_process'; +import { isAbsolute, join, relative, sep } from 'node:path'; +import type { ClaudeTranscriptReader } from '../src/agents/claude-terminal-recovery.js'; +import { CODING_CONTAINER_AGENT, codingContainerAgentExecOptions } + from '../src/runtime/coding-container-policy.js'; + +// Read as the transcript owner. Claude creates private files while the controller +// has no DAC override; the final transcript handback cannot serve a live reader. +export const CONTAINER_CLAUDE_TRANSCRIPT_READ = ` +const fs = require('node:fs'), path = require('node:path'); +const [root, name, offset, count] = process.argv.slice(1); +if (name === '') { + const files = fs.readdirSync(root, { recursive: true, withFileTypes: true }) + .filter(entry => entry.isFile() && entry.name.endsWith('.jsonl')) + .map(entry => path.join(entry.parentPath, entry.name)) + .map(file => [path.relative(root, file), fs.statSync(file).size, fs.statSync(file).mtimeMs]); + process.stdout.write(JSON.stringify(files)); +} else { + const file = path.resolve(root, name), resolvedRoot = fs.realpathSync(root); + if (!file.endsWith('.jsonl') || !fs.realpathSync(file).startsWith(resolvedRoot + path.sep)) { + throw new Error('transcript is outside the attempt directory'); + } + const start = Number(offset), length = Number(count); + if (!Number.isSafeInteger(start) || start < 0 || !Number.isSafeInteger(length) || length < 0) { + throw new Error('invalid transcript range'); + } + const buffer = Buffer.alloc(length), fd = fs.openSync(file, 'r'); + try { process.stdout.write(buffer.subarray(0, fs.readSync(fd, buffer, 0, length, start))); } + finally { fs.closeSync(fd); } +} +`; + +export function containerClaudeTranscriptReader(containerId: string, directory: string, + env: NodeJS.ProcessEnv): ClaudeTranscriptReader { + if (!/^[a-f0-9]{64}$/.test(containerId)) throw new Error('transcript reader requires an exact container ID'); + const root = `${CODING_CONTAINER_AGENT.home}/.claude/projects/-app`; + const read = (name: string, start = 0, length = 0): Buffer => execFileSync('docker', [ + 'exec', ...codingContainerAgentExecOptions(), containerId, 'node', '-e', + CONTAINER_CLAUDE_TRANSCRIPT_READ, root, name, String(start), String(length), + ], { env, timeout: 5_000, maxBuffer: 256 * 1024 * 1024 }); + return { + snapshot() { + const entries: [string, number][] = JSON.parse(read('').toString('utf8')); + return new Map(entries.map(([name, size]) => [join(directory, name), size])); + }, + read(path, start, length) { + const name = relative(directory, path); + if (!name || isAbsolute(name) || name.split(sep).includes('..')) { + throw new Error('transcript is outside the attempt directory'); + } + return read(name.split(sep).join('/'), start, length); + }, + }; +} diff --git a/tools/stack-bench/container/coding-providers.ts b/tools/stack-bench/container/coding-providers.ts new file mode 100644 index 00000000000..4ebc7a24313 --- /dev/null +++ b/tools/stack-bench/container/coding-providers.ts @@ -0,0 +1,112 @@ +import { appendFileSync, existsSync } from 'node:fs'; +import { homedir } from 'node:os'; +import { join, resolve } from 'node:path'; +import { codexArguments, codexTranscriptDirectory, parseCodexResult, runCodexProcess } + from '../src/agents/codex-protocol.js'; +import { claudeRatesForModel } from '../src/evidence/claude-usage-cost.js'; +import { runTranscriptAwareProcess } from '../src/agents/claude-terminal-recovery.js'; +import type { PricingRates } from '../src/evidence/pricing-authority.js'; +import { containerClaudeTranscriptReader } from './claude-transcript-reader.js'; +import { CODING_CONTAINER_AGENT, CODING_CONTAINER_APP_ROOT } from '../src/runtime/coding-container-policy.js'; +import { validateClaudeNativeSession, validateCodexNativeSession } + from '../src/agents/native-session-validation.js'; + +type Invocation = { model: string; effort: string; baseUrl: string; resumeSession: string | null; + maxBudgetUsd: string | null }; +type ProcessOptions = Parameters[0] & { + projects: string; containerId: string; marker: string; model: string; + pricingRates: PricingRates | null; resumeSession: string | null; +}; +interface CodingProvider { + requiresBudget: boolean; + executable: string; + apiKeyEnvironment: string; + credentialPath?: string; + containerTranscripts: string; + tokenEnvironment: string; + environment(baseUrl: string): string[]; + projects(appDir: string): string; + rates(model: string): PricingRates | null; + args(options: Invocation): string[]; + run(options: ProcessOptions): ReturnType; + result(stdout: string, appDir: string, invocationToken: string): Record | null; + validateContinuation(directory: string, sessionId: string, model: string): void; +} + +const codexProvider: CodingProvider = { + requiresBudget: true, + executable: 'codex', apiKeyEnvironment: 'OPENAI_API_KEY', + containerTranscripts: `${CODING_CONTAINER_AGENT.home}/.codex/sessions`, + tokenEnvironment: 'MODEL_PROXY_TOKEN', + environment: () => [`CODEX_HOME=${CODING_CONTAINER_AGENT.home}/.codex`], + projects: appDir => join(codexTranscriptDirectory(appDir), 'sessions'), + rates: () => null, + args: codexArguments, + run: runCodexProcess, + validateContinuation: validateCodexNativeSession, + result: (stdout, appDir, invocationToken) => { + const result = parseCodexResult(stdout); + const sessionId = result.session_id; + const eventFile = typeof sessionId === 'string' && /^[0-9a-f-]{36}$/i.test(sessionId) + ? `${sessionId}.events.jsonl` : `interrupted-${invocationToken}.events.jsonl`; + const path = join(codexTranscriptDirectory(appDir), eventFile); + const header = existsSync(path) ? '' : `${JSON.stringify({ type: 'stack_bench_context', cwd: '/app' })}\n`; + appendFileSync(path, `${header}${stdout}\n`, { mode: 0o600 }); + return result; + }, +}; + +export const CODING_PROVIDERS = { + anthropic: { + requiresBudget: false, + executable: 'claude', apiKeyEnvironment: 'ANTHROPIC_API_KEY', + credentialPath: join(homedir(), '.claude', '.credentials.json'), + containerTranscripts: `${CODING_CONTAINER_AGENT.home}/.claude/projects/-app`, + tokenEnvironment: 'ANTHROPIC_AUTH_TOKEN', + environment: baseUrl => [`ANTHROPIC_BASE_URL=${baseUrl}`, 'DISABLE_AUTOUPDATER=1', 'FORCE_PROMPT_CACHING_5M=1'], + projects: appDir => join(homedir(), '.claude', 'projects', + resolve(appDir).replace(/[\\/:]/g, '-').toLowerCase()), + rates: claudeRatesForModel, + validateContinuation: validateClaudeNativeSession, + args: ({ model, effort, maxBudgetUsd, resumeSession }) => { + return [ + '--print', '--output-format', 'json', + // Isolate the session from project memory, plugins, and integrations. + '--bare', + '--permission-mode', 'acceptEdits', + '--settings', JSON.stringify({ permissions: { allow: ['Bash'] } }), + '--effort', effort, + '--model', model, + ...(maxBudgetUsd !== null ? ['--max-budget-usd', maxBudgetUsd] : []), + // The app is the only directory a session may reach; inside the container + // that is all there is, but the flag is kept so host and container runs are + // configured identically. + '--add-dir', CODING_CONTAINER_APP_ROOT, + ...(resumeSession !== null ? ['--resume', resumeSession] : []), + ]; + }, + run: options => { + const transcriptReader = containerClaudeTranscriptReader(options.containerId, options.projects, options.env); + return runTranscriptAwareProcess({ ...options, transcriptDirectory: options.projects, + transcriptReader, transcriptSnapshot: transcriptReader.snapshot(), pollMs: 1_000 }); + }, + result: stdout => { + try { return JSON.parse(stdout); } + catch { + for (const line of stdout.split(/\r?\n/).reverse()) { + try { return JSON.parse(line); } catch { /* Keep looking. */ } + } + } + return null; + }, + }, + openai: codexProvider, + openrouter: { ...codexProvider, apiKeyEnvironment: 'OPENROUTER_API_KEY' }, +} satisfies Record; + +export type CodingProviderId = keyof typeof CODING_PROVIDERS; + +export function parseCodingProvider(value: string): CodingProviderId { + if (!Object.hasOwn(CODING_PROVIDERS, value)) throw new Error(`unsupported coding provider: ${value}`); + return value as CodingProviderId; +} diff --git a/tools/stack-bench/container/container-auth.ts b/tools/stack-bench/container/container-auth.ts new file mode 100644 index 00000000000..d52ff6c457b --- /dev/null +++ b/tools/stack-bench/container/container-auth.ts @@ -0,0 +1,99 @@ +import { readPinnedExecutionCredential } from '../src/agents/credential-profiles.js'; +import { existsSync, readFileSync } from 'node:fs'; +import type { PathLike } from 'node:fs'; +import { isAbsolute, resolve } from 'node:path'; + +export const SUBSCRIPTION_TOKEN_ENVIRONMENT = 'CLAUDE_CODE_OAUTH_TOKEN'; +export const LEGACY_SUBSCRIPTION_TOKEN_TARGET = '/run/secrets/claude-code-oauth-token'; + +export type ContainerAuth = { + provider?: 'anthropic' | 'openai' | 'openrouter'; + accountId?: string; + mode: 'api-key' | 'subscription-token'; + credential: string; +}; + +type ReadTextFile = (path: PathLike | number, encoding: BufferEncoding) => string; + +export interface ResolveContainerAuthOptions { + provider?: 'anthropic' | 'openai' | 'openrouter'; + apiKey?: string; + env?: NodeJS.ProcessEnv; + credentialsPath?: string; + exists?: (path: PathLike) => boolean; + read?: ReadTextFile; +} + +export function resolveContainerAuth({ provider = 'anthropic', apiKey = '', env = process.env, credentialsPath, + exists = existsSync, read = readFileSync as ReadTextFile }: ResolveContainerAuthOptions = {}): ContainerAuth { + const pinned = readPinnedExecutionCredential(env); + if (pinned) { + if (pinned.assignment.provider !== provider) throw new Error('Pinned credential provider does not match invocation'); + apiKey = pinned.assignment.mode === 'api-key' ? pinned.secret : ''; + // Resolve the broker credential from the same bytes that passed its pin check. + // Never reopen a file that an operator can replace between validation and use. + read = path => { + if (String(path) !== pinned.secretFile) throw new Error('Pinned credential file does not match invocation'); + return pinned.secret; + }; + } + if (provider === 'openrouter') { + if (!apiKey) throw new Error('OpenRouter requires an API key'); + return { provider, mode: 'api-key', credential: apiKey }; + } + if (provider === 'openai') { + const authFile = env.CODEX_AUTH_FILE?.trim(); + if (apiKey && authFile) throw new Error('use only one of OpenAI API-key and account authentication'); + if (apiKey) return { provider, mode: 'api-key', credential: apiKey }; + if (!authFile) throw new Error('OpenAI requires an API key or an explicit CODEX_AUTH_FILE'); + if (!isAbsolute(authFile)) throw new Error('CODEX_AUTH_FILE must be an absolute path'); + if (!exists(authFile)) throw new Error('CODEX_AUTH_FILE does not exist'); + let auth: { auth_mode?: string; OPENAI_API_KEY?: unknown; + tokens?: { access_token?: unknown; account_id?: unknown } }; + try { auth = JSON.parse(read(authFile, 'utf8')); } + catch { throw new Error('CODEX_AUTH_FILE must contain valid Codex login JSON'); } + if (!auth || auth.OPENAI_API_KEY || auth.auth_mode !== 'chatgpt' + || typeof auth.tokens?.access_token !== 'string' || !auth.tokens.access_token.trim() + || typeof auth.tokens.account_id !== 'string' || !auth.tokens.account_id.trim()) { + throw new Error('CODEX_AUTH_FILE must contain ChatGPT account login tokens, not an API key'); + } + let expiry: unknown; + try { expiry = JSON.parse(Buffer.from(auth.tokens.access_token.split('.')[1]!, 'base64url').toString()).exp; } + catch { throw new Error('Codex account access token has no valid expiry; log in again'); } + if (typeof expiry !== 'number' || !Number.isFinite(expiry) || expiry * 1000 <= Date.now()) { + throw new Error('Codex account access token is expired; log in again and replace CODEX_AUTH_FILE'); + } + // Each broker uses an access-token snapshot. It never rotates shared refresh tokens. + return { provider, mode: 'subscription-token', credential: auth.tokens.access_token, + accountId: auth.tokens.account_id }; + } + const token = String(env[SUBSCRIPTION_TOKEN_ENVIRONMENT] ?? '').trim(); + const tokenFileValue = String(env[`${SUBSCRIPTION_TOKEN_ENVIRONMENT}_FILE`] ?? '').trim(); + if (token && tokenFileValue) { + throw new Error(`use only one of ${SUBSCRIPTION_TOKEN_ENVIRONMENT} and ` + + `${SUBSCRIPTION_TOKEN_ENVIRONMENT}_FILE`); + } + if (apiKey && (token || tokenFileValue)) { + throw new Error('use only one of API-key and subscription-token authentication'); + } + if (apiKey) return { mode: 'api-key', credential: apiKey }; + if (token) return { mode: 'subscription-token', credential: token }; + if (tokenFileValue) { + if (!isAbsolute(tokenFileValue)) { + throw new Error(`${SUBSCRIPTION_TOKEN_ENVIRONMENT}_FILE must be an absolute path`); + } + const source = resolve(tokenFileValue); + if (!exists(source)) throw new Error(`subscription token file does not exist: ${source}`); + const credential = String(read(source, 'utf8')).trim(); + if (!credential) { + throw new Error(`subscription token file is empty: ${source}`); + } + return { mode: 'subscription-token', credential }; + } + if (credentialsPath && exists(credentialsPath)) { + throw new Error('rotating Claude credential files cannot be isolated from generated shell commands; ' + + 'select an API key or CLAUDE_CODE_OAUTH_TOKEN_FILE'); + } + throw new Error(`no API key, ${SUBSCRIPTION_TOKEN_ENVIRONMENT}, ` + + `${SUBSCRIPTION_TOKEN_ENVIRONMENT}_FILE, or credentials file is available`); +} diff --git a/tools/stack-bench/container/credential-broker-accounting.ts b/tools/stack-bench/container/credential-broker-accounting.ts new file mode 100644 index 00000000000..eb8285f101b --- /dev/null +++ b/tools/stack-bench/container/credential-broker-accounting.ts @@ -0,0 +1,376 @@ +import type { ProviderFailure } from '../src/agents/provider-failure.js'; +import { randomBytes } from 'node:crypto'; +import { readFileSync, renameSync, rmSync, writeFileSync } from 'node:fs'; +import { z } from 'zod'; + +import { normalizeClaudeUsage, priceClaudeUsage } from '../src/evidence/claude-usage-cost.js'; +import type { ClaudeUsage } from '../src/evidence/claude-usage-cost.js'; +import { validatePricingRates as validateSharedPricingRates } from '../src/evidence/pricing-authority.js'; +import { formatZodError } from '../src/zod-error.js'; + +export const BROKER_LEDGER_SCHEMA_VERSION = 4; +// Why a billable request was charged its cost ceiling instead of priced from +// the provider's usage: a 2xx response without complete usage (an aborted or +// errored stream, an oversized body), a response that broke off, or an +// upstream connection that failed. The ceiling makes spend an upper bound. +export const ESTIMATE_REASONS = ['no-usage', 'response-aborted', 'upstream-error'] as const; +export type EstimateReason = typeof ESTIMATE_REASONS[number]; +export type EstimateCounts = Record; +export const noEstimates = (): EstimateCounts => ({ 'no-usage': 0, 'response-aborted': 0, 'upstream-error': 0 }); +export const MAX_BROKER_OUTPUT_TOKENS = 128_000; +export const CLAUDE_USAGE_FIELDS = ['input', 'output', 'cacheRead', 'cacheWrite5m', 'cacheWrite1h'] as const; +const COST_TOLERANCE_USD = 0.0001; + +type JsonRecord = Record; +export type BrokerMode = 'api-key' | 'subscription-token'; +export type PricingRates = ReturnType; + +export type BrokerConfig = { + provider?: 'anthropic' | 'openai' | 'openrouter'; + accountId?: string; + providerRoute?: string; + mode: BrokerMode; + credential: string; + sessionToken: string; + readyPath?: string; + parentPid?: number; + expiresAt?: number; + listenHost?: '127.0.0.1' | '0.0.0.0'; + ledgerPath?: string; + model: string; + maxOutputTokens: number; + maxBudgetUsd?: number | null; + pricingRates?: PricingRates; +}; + +export type BrokerLedger = { + provider?: 'openrouter'; + providerRoute?: string; + providerReportedCostUsd?: number; + upstreamProviders?: string[]; + providerIntegrityError?: string; + providerFailure?: ProviderFailure | null; + schemaVersion: number; + model: string; + maxBudgetUsd: number | null; + acceptedRequests: number; + billableRequests: number; + completedBillableRequests: number; + estimatedBillableRequests: number; + estimatedByReason: EstimateCounts; + spentUsd: number; + reservedUsd: number; + usage: ClaudeUsage; + complete: boolean; + updatedAt: string; +}; + +// `costUsd` is what the broker charged: exact provider usage priced at the +// receipt's rates, plus the cost ceiling of every estimated request. With +// `exact` false it is an upper bound and `calculatedCostUsd`, priced from the +// exact usage alone, a lower bound. +export interface CredentialBrokerReceipt { + costSource?: 'provider-reported'; + provider?: 'openrouter'; + providerRoute?: string; + providerReportedCostUsd?: number; + upstreamProviders?: string[]; + schemaVersion: 3; + source: 'credential-broker'; + model: string; + maxBudgetUsd: number; + costUsd: number; + cliCostUsd: number | null; + calculatedCostUsd: number | null; + usage: ClaudeUsage | null; + pricingRates: PricingRates | null; + exact: boolean; + estimatedRequests: number; + estimatedByReason: EstimateCounts; + complete: boolean; + reconciled: boolean; + error: string | null; +} + +export interface CredentialBrokerResult extends JsonRecord { + total_cost_usd: number; + usage?: ReturnType; + stack_bench_cost_receipt: CredentialBrokerReceipt; +} + +const positiveFinite = z.number().finite().positive(); +const nonNegativeFinite = z.number().finite().nonnegative(); +const nonNegativeSafeInteger = z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER); +const usageSchema = z.strictObject({ + input: nonNegativeSafeInteger, + output: nonNegativeSafeInteger, + cacheRead: nonNegativeSafeInteger, + cacheWrite5m: nonNegativeSafeInteger, + cacheWrite1h: nonNegativeSafeInteger, +}); +const brokerConfigSchema = z.strictObject({ + provider: z.enum(['anthropic', 'openai', 'openrouter']).optional(), + accountId: z.string().min(1).optional(), + providerRoute: z.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9._/-]{0,127}$/).optional(), + mode: z.enum(['api-key', 'subscription-token']), + credential: z.string().min(16), + sessionToken: z.string().min(16), + readyPath: z.string().min(1).optional(), + parentPid: z.number().int().positive().max(Number.MAX_SAFE_INTEGER).optional(), + expiresAt: positiveFinite.optional(), + listenHost: z.enum(['127.0.0.1', '0.0.0.0']).optional(), + ledgerPath: z.string().min(1).optional(), + model: z.string().min(1), + maxOutputTokens: z.number().int().min(1).max(MAX_BROKER_OUTPUT_TOKENS), + maxBudgetUsd: positiveFinite.nullable().optional(), + pricingRates: z.unknown().optional(), +}).superRefine((value, context) => { + if (value.provider === 'openrouter' && (value.mode !== 'api-key' || !value.providerRoute || value.maxBudgetUsd == null)) { + context.addIssue({ code: 'custom', message: 'OpenRouter requires API-key auth, providerRoute, and a spend budget' }); + } + if (value.provider !== 'openrouter' && value.providerRoute !== undefined) { + context.addIssue({ code: 'custom', path: ['providerRoute'], message: 'only OpenRouter uses providerRoute' }); + } + if (value.expiresAt !== undefined && value.expiresAt <= Date.now()) { + context.addIssue({ code: 'custom', path: ['expiresAt'], message: 'must be in the future' }); + } +}); +const brokerLedgerSchema = z.strictObject({ + provider: z.literal('openrouter').optional(), + providerRoute: z.string().min(1).optional(), + providerReportedCostUsd: nonNegativeFinite.optional(), + upstreamProviders: z.array(z.string().min(1).max(128)).optional(), + providerIntegrityError: z.string().max(200).optional(), + providerFailure: z.strictObject({ + category: z.enum(['rate-limit', 'quota', 'authentication', 'transport', 'request', 'broker-budget']), + status: z.number().int().min(100).max(599).nullable(), + code: z.string().regex(/^[a-zA-Z0-9_.-]{1,100}$/).nullable(), + budget: z.strictObject({ + maxBudgetUsd: positiveFinite, + spentUsd: nonNegativeFinite, + estimatedSpendUsd: nonNegativeFinite, + reservedUsd: nonNegativeFinite, + requestCeilingUsd: nonNegativeFinite, + }).optional(), + }).nullable().optional(), + schemaVersion: z.literal(BROKER_LEDGER_SCHEMA_VERSION), + model: z.string().min(1), + maxBudgetUsd: positiveFinite.nullable(), + acceptedRequests: nonNegativeSafeInteger, + billableRequests: nonNegativeSafeInteger, + completedBillableRequests: nonNegativeSafeInteger, + estimatedBillableRequests: nonNegativeSafeInteger, + estimatedByReason: z.strictObject({ + 'no-usage': nonNegativeSafeInteger, + 'response-aborted': nonNegativeSafeInteger, + 'upstream-error': nonNegativeSafeInteger, + }), + spentUsd: nonNegativeFinite, + reservedUsd: nonNegativeFinite, + usage: usageSchema, + complete: z.boolean(), + updatedAt: z.string().refine(value => !Number.isNaN(Date.parse(value)), 'must be a timestamp'), +}); + +function isRecord(value: unknown): value is JsonRecord { + return value !== null && typeof value === 'object' && !Array.isArray(value); +} + +function isNumber(value: unknown): value is number { + return typeof value === 'number'; +} + +function errorMessage(error: unknown): string { + return error instanceof Error ? error.message : String(error); +} + +function fail(message: string): never { + throw new Error(`credential broker: ${message}`); +} + +export function validatePricingRates(value: unknown): PricingRates { + try { return validateSharedPricingRates(value, { at: 'pricingRates' }); } + catch (error) { return fail(errorMessage(error)); } +} + +export function priceNormalizedClaudeUsage(usage: ClaudeUsage, rates: PricingRates): number { + return priceClaudeUsage({ + input_tokens: usage.input, + output_tokens: usage.output, + cache_read_input_tokens: usage.cacheRead, + cache_creation: { + ephemeral_5m_input_tokens: usage.cacheWrite5m, + ephemeral_1h_input_tokens: usage.cacheWrite1h, + }, + }, rates); +} + +function rawUsage(usage: ClaudeUsage): JsonRecord { + return { + input_tokens: usage.input, + output_tokens: usage.output, + cache_read_input_tokens: usage.cacheRead, + cache_creation_input_tokens: usage.cacheWrite5m + usage.cacheWrite1h, + cache_creation: { + ephemeral_5m_input_tokens: usage.cacheWrite5m, + ephemeral_1h_input_tokens: usage.cacheWrite1h, + }, + }; +} + +function brokerCoversCliUsage(broker: ClaudeUsage, cli: ClaudeUsage): boolean { + return broker.input >= cli.input + && broker.output >= cli.output + && broker.cacheRead >= cli.cacheRead + && broker.cacheWrite5m + broker.cacheWrite1h >= cli.cacheWrite5m + cli.cacheWrite1h; +} + +export function validateBrokerConfig(value: unknown): BrokerConfig { + const parsed = brokerConfigSchema.safeParse(value); + if (!parsed.success) fail(formatZodError(parsed.error, 'configuration')); + const { pricingRates, ...config } = parsed.data; + return config.maxBudgetUsd === null || config.maxBudgetUsd === undefined + ? config + : { ...config, pricingRates: validatePricingRates(pricingRates) }; +} + +function validateLedger(value: unknown, + { model = null, maxBudgetUsd = undefined }: { model?: string | null; maxBudgetUsd?: number | null } = {}): BrokerLedger { + const parsed = brokerLedgerSchema.safeParse(value); + if (!parsed.success) fail(formatZodError(parsed.error, 'spend ledger')); + const ledger = parsed.data; + if (model !== null && ledger.model !== model) fail('spend ledger model does not match'); + if (maxBudgetUsd !== undefined && ledger.maxBudgetUsd !== maxBudgetUsd) { + fail('spend ledger budget does not match'); + } + if (ledger.completedBillableRequests > ledger.billableRequests) { + fail('spend ledger completed request count is invalid'); + } + if (ledger.estimatedBillableRequests > ledger.completedBillableRequests) { + fail('spend ledger estimated request count is invalid'); + } + const reasons = ESTIMATE_REASONS.reduce((sum, reason) => sum + ledger.estimatedByReason[reason], 0); + if (reasons !== ledger.estimatedBillableRequests) fail('spend ledger estimate reasons do not add up'); + const complete = ledger.reservedUsd === 0 + && ledger.completedBillableRequests === ledger.billableRequests; + if (ledger.complete !== complete) fail('spend ledger completion state is invalid'); + if (ledger.provider === 'openrouter' && (!ledger.providerRoute || ledger.providerReportedCostUsd === undefined + || !ledger.upstreamProviders || ledger.providerReportedCostUsd > ledger.spentUsd + COST_TOLERANCE_USD)) { + fail('OpenRouter spend ledger lacks valid cost and routing provenance'); + } + return ledger; +} + +export function writeCredentialBrokerLedger(path: string | undefined, value: unknown): void { + if (!path) return; + const ledger = validateLedger(value); + const temporary = `${path}.${process.pid}.${randomBytes(8).toString('hex')}.tmp`; + writeFileSync(temporary, `${JSON.stringify(ledger)}\n`, { flag: 'wx', mode: 0o600 }); + try { renameSync(temporary, path); } + catch (error) { rmSync(temporary, { force: true }); throw error; } +} + +export function readCredentialBrokerLedger(path: string, + expected: { model?: string | null; maxBudgetUsd?: number | null } = {}): BrokerLedger { + return validateLedger(JSON.parse(readFileSync(path, 'utf8')), expected); +} + +export function reconcileCredentialBrokerReceipt({ ledger, cliResult, model, maxBudgetUsd, + pricingRates, provider = 'anthropic', brokerDiagnostics = null, toleranceUsd = COST_TOLERANCE_USD }: { + provider?: 'anthropic' | 'openai' | 'openrouter'; + ledger: unknown; cliResult: unknown; model: unknown; maxBudgetUsd: unknown; pricingRates: unknown; + brokerDiagnostics?: unknown; toleranceUsd?: number; +}): { ok: boolean; result: CredentialBrokerResult; receipt: CredentialBrokerReceipt } { + if (typeof model !== 'string' || !model) fail('receipt model is invalid'); + if (!isNumber(maxBudgetUsd) || !Number.isFinite(maxBudgetUsd) || maxBudgetUsd <= 0) fail('receipt budget is invalid'); + if (!Number.isFinite(toleranceUsd) || toleranceUsd < 0) fail('receipt tolerance is invalid'); + const receiptBudget = maxBudgetUsd; + let verifiedLedger: BrokerLedger | null = null; + let verifiedRates: PricingRates | null = null; + let usage: ClaudeUsage | null = null; + let cliUsage: ClaudeUsage | null = null; + let calculatedCostUsd: number | null = null; + let issue: string | null = null; + try { verifiedLedger = validateLedger(ledger, { model, maxBudgetUsd: receiptBudget }); } + catch (error) { issue = errorMessage(error); } + if (!issue && verifiedLedger?.complete !== true) issue = 'credential broker spend ledger is incomplete'; + const estimatedRequests = verifiedLedger?.estimatedBillableRequests ?? 0; + const exact = verifiedLedger !== null && estimatedRequests === 0; + try { verifiedRates = validatePricingRates(pricingRates); } + catch (error) { if (!issue) issue = errorMessage(error); } + try { cliUsage = normalizeClaudeUsage(isRecord(cliResult) ? cliResult.usage : undefined); } + catch (error) { if (!issue) issue = errorMessage(error); } + if (verifiedLedger) usage = structuredClone(verifiedLedger.usage); + if (!issue && exact && cliUsage && usage && !brokerCoversCliUsage(usage, cliUsage)) { + issue = 'credential broker usage is lower than CLI usage totals'; + } + if (!issue && provider === 'openrouter' && verifiedLedger?.provider !== 'openrouter') issue = 'OpenRouter spend ledger lacks provenance'; + if (!issue && verifiedLedger?.providerIntegrityError) issue = verifiedLedger.providerIntegrityError; + try { if (provider !== 'openrouter' && verifiedRates && usage) calculatedCostUsd = priceNormalizedClaudeUsage(usage, verifiedRates); } + catch (error) { if (!issue) issue = errorMessage(error); } + const brokerCost = verifiedLedger + ? provider === 'openrouter' ? verifiedLedger.spentUsd + verifiedLedger.reservedUsd + : Math.min(receiptBudget, verifiedLedger.spentUsd + verifiedLedger.reservedUsd) : receiptBudget; + // Estimated requests contribute ceilings, not observed tokens. Require those + // ceilings to cover every usage component seen by either recorder. + if (!issue && provider !== 'openrouter' && !exact && verifiedRates && usage && cliUsage) { + const observedUsage = { ...usage }; + for (const field of CLAUDE_USAGE_FIELDS) { + observedUsage[field] = Math.max(usage[field], cliUsage[field]); + } + if (priceNormalizedClaudeUsage(observedUsage, verifiedRates) - brokerCost > toleranceUsd) { + issue = 'observed usage-priced spend exceeds credential broker spend ceiling'; + } + } + const cliCost = Number(isRecord(cliResult) ? cliResult.total_cost_usd : undefined); + if (!issue && (provider === 'anthropic' || (isRecord(cliResult) && cliResult.total_cost_usd !== undefined)) + && (!Number.isFinite(cliCost) || cliCost < 0)) { + issue = 'coding session did not return a usable cost receipt'; + } + // Exact spend must price back to the broker's figure. Estimated requests + // add their ceilings on top of the priced usage, so the priced usage can + // only fall below the broker's figure, never above it. + if (!issue && calculatedCostUsd !== null && exact && Math.abs(calculatedCostUsd - brokerCost) > toleranceUsd) { + issue = `usage-priced spend $${calculatedCostUsd.toFixed(6)} does not match credential broker spend $${brokerCost.toFixed(6)}`; + } + if (!issue && provider === 'openrouter' && brokerCost > receiptBudget + toleranceUsd) { + issue = 'OpenRouter reported spend exceeds the session budget'; + } + const receipt: CredentialBrokerReceipt = { + ...(provider === 'openrouter' ? { costSource: 'provider-reported' as const, provider, + providerRoute: verifiedLedger?.providerRoute, providerReportedCostUsd: verifiedLedger?.providerReportedCostUsd, + upstreamProviders: verifiedLedger?.upstreamProviders } : {}), + schemaVersion: 3, + source: 'credential-broker', + model, + maxBudgetUsd: receiptBudget, + costUsd: Number(brokerCost.toFixed(6)), + cliCostUsd: Number.isFinite(cliCost) && cliCost >= 0 ? Number(cliCost.toFixed(6)) : null, + calculatedCostUsd: calculatedCostUsd === null ? null : Number(calculatedCostUsd.toFixed(6)), + usage, + pricingRates: verifiedRates, + exact, + estimatedRequests, + estimatedByReason: verifiedLedger ? structuredClone(verifiedLedger.estimatedByReason) : noEstimates(), + complete: verifiedLedger?.complete === true, + reconciled: issue === null, + error: issue, + }; + const result: CredentialBrokerResult = { + ...(isRecord(cliResult) + ? structuredClone(cliResult) : { type: 'result', is_error: true, result: '' }), + total_cost_usd: receipt.costUsd, + stack_bench_cost_receipt: receipt, + }; + delete result.stack_bench_provider_failure; + if (verifiedLedger?.providerFailure) result.stack_bench_provider_failure = verifiedLedger.providerFailure; + if (usage) result.usage = rawUsage(usage); + if (brokerDiagnostics) result.stack_bench_credential_broker = structuredClone(brokerDiagnostics); + if (issue) { + result.is_error = true; + result.terminal_reason = 'cost_receipt_error'; + result.result = [typeof result.result === 'string' ? result.result.trim() : '', issue] + .filter(Boolean).join('\n'); + } + return { ok: issue === null, result, receipt }; +} diff --git a/tools/stack-bench/container/credential-broker-process.ts b/tools/stack-bench/container/credential-broker-process.ts new file mode 100644 index 00000000000..7cde7abdb0e --- /dev/null +++ b/tools/stack-bench/container/credential-broker-process.ts @@ -0,0 +1,401 @@ +import { spawn, spawnSync } from 'node:child_process'; +import type { ChildProcess } from 'node:child_process'; +import { randomBytes } from 'node:crypto'; +import { chmodSync, existsSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { isAbsolute, join } from 'node:path'; +import { setTimeout as wait } from 'node:timers/promises'; + +import type { ContainerAuth } from './container-auth.js'; +import { MAX_BROKER_OUTPUT_TOKENS, readCredentialBrokerLedger, validateBrokerConfig } + from './credential-broker-accounting.js'; +import type { BrokerLedger, PricingRates } from './credential-broker-accounting.js'; +import { compiledEntrypoint } from '../src/package-root.js'; +import { killTree } from '../src/runtime/platform.js'; +import { ATTEMPT_CREATION_LABEL } from '../src/runtime/container-identity.js'; +import { BROKER_CONTAINER_RESOURCE_LIMITS } from '../src/composition/product-config.js'; + +const BROKER_DRAIN_TIMEOUT_MS = 30_000; +const BROKER_DRAIN_POLL_MS = 100; +const BROKER_STDERR_LIMIT_BYTES = 16 * 1024; +const BROKER_STOP_GRACE_MS = 2_000; +const BROKER_STOP_FORCE_MS = 2_000; + +type JsonRecord = Record; +type Alive = (pid: number | undefined) => boolean; + +export type BrokerProcessState = { + exitCode: number | null; + signal: NodeJS.Signals | null; + exitedAt: string | null; + stderrTail: string; + stderrPending: string; + stderrTruncated: boolean; +}; + +export type BrokerError = { type: string; phase: string; message: string }; + +export type BrokerDiagnostics = { + schemaVersion: number; + endpointKind: string; + child: { pid: number | undefined | null; exitCode: number | null; signal: NodeJS.Signals | null; + exitedAt: string | null; stderrTail: string | null; stderrTruncated: boolean }; + drain: { timeoutMs: number; elapsedMs: number; timedOut: boolean; reason: string | null; + terminationRequested: boolean } | null; + termination: { gracefulRequested: boolean; forceRequested: boolean; exited: boolean; + gracefulTimeoutMs: number; forceTimeoutMs: number } | null; + ledger: BrokerLedger | null; + errors: BrokerError[]; +}; + +export interface CredentialBrokerChild { + pid?: number; + exitCode?: number | null; + signalCode?: NodeJS.Signals | null; + kill?: (signal?: NodeJS.Signals | number) => boolean; +} + +export interface CredentialBrokerHandle { + child: CredentialBrokerChild; + root: string; + ledgerPath: string; + model: string; + maxBudgetUsd: number | null; + sessionToken?: string; + baseUrl?: string; + listenHost?: string; + endpointKind?: string; + processState?: Partial; + diagnosticSecrets?: string[]; + finalDiagnostics?: BrokerDiagnostics | null; + finalLedger?: BrokerLedger | null; + container?: CredentialBrokerContainer; +} + +export type CredentialBrokerContainer = { + name: string; id: string; image: string; owned: true; networkMode: string; +}; + +export type CredentialBrokerDockerOptions = { + imageId: string; + networkContainerId: string; + // The caller persists this intent before creating any resource. + name: string; + creationToken: string; + // This private path must be mounted at the identical path on the Docker host. + privateDirectory: string; + onCreated: (container: CredentialBrokerContainer) => void; +}; + +function brokerDocker(args: string[]): string { + const result = spawnSync('docker', args, { encoding: 'utf8', timeout: 10_000, windowsHide: true }); + if (result.status !== 0) throw new Error(`credential broker Docker ${args[0]} failed: ` + + (result.stderr || result.error?.message || `exit ${result.status}`).trim()); + return result.stdout.trim(); +} + +function signalBrokerContainer(container: CredentialBrokerContainer, signal: 'TERM' | 'KILL'): void { + brokerDocker(['kill', '--signal', signal, container.id]); +} + +export interface CredentialBroker extends CredentialBrokerHandle { + child: ChildProcess; + sessionToken: string; + baseUrl: string; + listenHost: string; + endpointKind: string; + processState: BrokerProcessState; + diagnosticSecrets: string[]; + finalDiagnostics: BrokerDiagnostics | null; + finalLedger: BrokerLedger | null; +} + +function isRecord(value: unknown): value is JsonRecord { + return value !== null && typeof value === 'object' && !Array.isArray(value); +} + +function fail(message: string): never { + throw new Error(`credential broker: ${message}`); +} + +function redactDiagnosticText(value: unknown, + broker: CredentialBrokerHandle | string[] | null | undefined): string { + let result = String(value ?? ''); + const secrets = Array.isArray(broker) ? broker : broker?.diagnosticSecrets ?? []; + for (const secret of secrets) { + if (typeof secret === 'string' && secret) result = result.replaceAll(secret, '[REDACTED]'); + } + return result; +} + +function appendDiagnosticStderr(state: BrokerProcessState, chunk: string, secrets: string[], flush = false): void { + const raw = state.stderrPending + chunk; + let redacted = redactDiagnosticText(raw, secrets); + let pendingLength = 0; + if (!flush) { + for (const secret of secrets) { + for (let length = Math.min(secret.length - 1, redacted.length); length > pendingLength; length -= 1) { + if (redacted.endsWith(secret.slice(0, length))) { pendingLength = length; break; } + } + } + } else if (raw && secrets.some(secret => secret.startsWith(raw))) redacted = '[REDACTED]'; + state.stderrPending = pendingLength ? redacted.slice(-pendingLength) : ''; + const safe = pendingLength ? redacted.slice(0, -pendingLength) : redacted; + const next = state.stderrTail + safe; + if (Buffer.byteLength(next) > BROKER_STDERR_LIMIT_BYTES) { + state.stderrTruncated = true; + state.stderrTail = Buffer.from(next).subarray(-BROKER_STDERR_LIMIT_BYTES).toString('utf8'); + } else state.stderrTail = next; +} + +export async function startCredentialBroker(selectedAuth: ContainerAuth, { networkMode, deadlineMs, + model, providerRoute, maxOutputTokens = MAX_BROKER_OUTPUT_TOKENS, maxBudgetUsd = null, pricingRates = null, + env = process.env, docker }: { networkMode: string; deadlineMs: number; model: string; + maxOutputTokens?: number; maxBudgetUsd?: number | null; pricingRates?: PricingRates | null; + providerRoute?: string; + env?: NodeJS.ProcessEnv; docker?: CredentialBrokerDockerOptions }): Promise { + if (!['bridge', 'host'].includes(networkMode) + && (!docker || networkMode !== `container:${docker.networkContainerId}`)) fail('network mode is invalid'); + if (!Number.isFinite(deadlineMs) || deadlineMs <= 0) fail('deadline is invalid'); + const credential = selectedAuth.credential.trim(); + if (!credential) fail('selected authentication has no broker credential'); + if (docker) { + if (process.platform !== 'linux' || !isAbsolute(docker.privateDirectory)) { + fail('Docker broker requires a Linux controller and an absolute shared private directory'); + } + if (!/^sha256:[a-f0-9]{64}$/.test(docker.imageId) + || !/^[a-f0-9]{64}$/.test(docker.networkContainerId) + || !/^[a-z0-9][a-z0-9_.-]{0,127}$/.test(docker.name) + || !/^[a-f0-9]{32,64}$/.test(docker.creationToken)) fail('Docker broker identity is invalid'); + } + const root = mkdtempSync(join(docker?.privateDirectory ?? tmpdir(), 'stack-bench-credential-broker-')); + let child: ChildProcess | null = null; + let container: CredentialBrokerContainer | undefined; + const processState: BrokerProcessState = { exitCode: null, signal: null, exitedAt: null, + stderrTail: '', stderrPending: '', stderrTruncated: false }; + try { + chmodSync(root, 0o700); + const configPath = join(root, 'config.json'); + const readyPath = join(root, 'ready.json'); + const ledgerPath = join(root, 'spend-ledger.json'); + const sessionToken = randomBytes(32).toString('hex'); + const listenHost = docker || networkMode === 'host' ? '127.0.0.1' : '0.0.0.0'; + const config = validateBrokerConfig({ provider: selectedAuth.provider, providerRoute, accountId: selectedAuth.accountId, + mode: selectedAuth.mode, credential, sessionToken, readyPath, + ...(docker ? {} : { parentPid: process.pid }), + expiresAt: Date.now() + deadlineMs + 60_000, listenHost, ledgerPath, + model, maxOutputTokens, maxBudgetUsd, pricingRates }); + writeFileSync(configPath, `${JSON.stringify(config)}\n`, { flag: 'wx', mode: 0o600 }); + if (docker) { + const network = `container:${docker.networkContainerId}`; + const id = brokerDocker(['create', '--name', docker.name, + '--label', `${ATTEMPT_CREATION_LABEL}=${docker.creationToken}`, + '--network', network, '--cap-drop', 'ALL', '--security-opt', 'no-new-privileges:true', + '--read-only', '--pids-limit', String(BROKER_CONTAINER_RESOURCE_LIMITS.pids), + '--memory', String(BROKER_CONTAINER_RESOURCE_LIMITS.memoryBytes), + '--memory-swap', String(BROKER_CONTAINER_RESOURCE_LIMITS.memoryBytes), + '--mount', `type=bind,src=${root},dst=${root}`, + '--entrypoint', 'node', docker.imageId, + '/opt/stack-bench/dist/container/credential-broker.js', '--config', configPath]); + if (!/^[a-f0-9]{64}$/.test(id)) fail('Docker broker did not return a container ID'); + container = { id, name: docker.name, image: docker.imageId, owned: true, networkMode: network }; + docker.onCreated(container); + } + child = spawn(container ? 'docker' : process.execPath, + container ? ['start', '--attach', container.id] + : [compiledEntrypoint('container', 'credential-broker.js'), '--config', configPath], { + stdio: ['ignore', 'ignore', 'pipe'], + windowsHide: true, + env: Object.fromEntries(['PATH', 'Path', 'SystemRoot', 'WINDIR', 'SSL_CERT_FILE', + 'NODE_EXTRA_CA_CERTS', 'HTTPS_PROXY', 'HTTP_PROXY'] + .filter(name => env[name] !== undefined).map(name => [name, env[name]])), + }); + const diagnosticSecrets = [credential, sessionToken]; + child.stderr?.on('data', (chunk: Buffer) => appendDiagnosticStderr( + processState, chunk.toString('utf8'), diagnosticSecrets)); + child.once('exit', (code: number | null, signal: NodeJS.Signals | null) => { + appendDiagnosticStderr(processState, '', diagnosticSecrets, true); + processState.exitCode = code; + processState.signal = signal; + processState.exitedAt = new Date().toISOString(); + }); + let spawnError: Error | null = null; + child.once('error', (error: Error) => { spawnError = error; }); + const readyDeadline = Date.now() + 10_000; + while (!spawnError && child.exitCode === null && !existsSync(readyPath) && Date.now() < readyDeadline) { + await wait(100); + } + if (spawnError) throw spawnError; + if (!existsSync(readyPath)) throw new Error(`credential broker did not become ready${processState.stderrTail ? `: ${processState.stderrTail}` : ''}`); + const ready: unknown = JSON.parse(readFileSync(readyPath, 'utf8')); + if (!isRecord(ready) || typeof ready.port !== 'number' || !Number.isInteger(ready.port) + || ready.port < 1 || ready.port > 65_535) throw new Error('credential broker returned an invalid port'); + if (ready.host !== listenHost) throw new Error('credential broker returned an invalid host'); + const host = docker || networkMode === 'host' ? '127.0.0.1' : 'host.docker.internal'; + return { child, root, ledgerPath, model, maxBudgetUsd: maxBudgetUsd ?? null, + sessionToken, baseUrl: `http://${host}:${ready.port}`, listenHost, + endpointKind: docker ? 'container-credential-broker' : 'local-credential-broker', processState, + ...(container ? { container } : {}), + diagnosticSecrets, finalDiagnostics: null, finalLedger: null }; + } catch (error) { + // Keep private authority when Docker cleanup fails. Recovery uses the saved exact ID. + if (container) brokerDocker(['rm', '-f', container.id]); + if (child?.pid) killTree(child.pid); + rmSync(root, { recursive: true, force: true }); + throw error; + } +} + +function processAlive(pid: number | undefined): boolean { + if (typeof pid !== 'number' || !Number.isInteger(pid) || pid < 1) return false; + try { process.kill(pid, 0); return true; } + catch (error) { return !isRecord(error) || error.code !== 'ESRCH'; } +} + +function brokerExited(broker: CredentialBrokerHandle | null | undefined, alive: Alive): boolean { + if (broker?.container) { + try { + return brokerDocker(['inspect', '--format', '{{.State.Running}}', broker.container.id]) === 'false'; + } catch { + // Docker unavailability is not proof that a provider-capable process stopped. + return false; + } + } + const state = broker?.processState; + if (!state) return !alive(broker?.child?.pid); + if (state.exitedAt || state.exitCode !== null && state.exitCode !== undefined + || state.signal !== null && state.signal !== undefined + || broker?.child?.exitCode !== null && broker?.child?.exitCode !== undefined + || broker?.child?.signalCode !== null && broker?.child?.signalCode !== undefined) return true; + return !alive(broker?.child?.pid); +} + +async function waitForBrokerExit(broker: CredentialBrokerHandle, timeoutMs: number, + { sleep, now, alive }: { sleep: (ms: number) => Promise; now: () => number; alive: Alive }): Promise { + const deadline = now() + timeoutMs; + while (!brokerExited(broker, alive) && now() < deadline) await sleep(BROKER_DRAIN_POLL_MS); + return brokerExited(broker, alive); +} + +export function credentialBrokerDiagnostics(broker: CredentialBrokerHandle | null): BrokerDiagnostics | null { + if (!broker) return null; + if (broker.finalDiagnostics) return structuredClone(broker.finalDiagnostics); + const state = broker.processState ?? {}; + return { + schemaVersion: 1, + endpointKind: broker.endpointKind ?? 'local-credential-broker', + child: { pid: broker.child?.pid ?? null, + exitCode: state.exitCode ?? broker.child?.exitCode ?? null, + signal: state.signal ?? broker.child?.signalCode ?? null, + exitedAt: state.exitedAt ?? null, + stderrTail: state.stderrTail ? redactDiagnosticText(state.stderrTail, broker) : null, + stderrTruncated: state.stderrTruncated === true }, + drain: null, + termination: null, + ledger: null, + errors: [], + }; +} + +export async function stopCredentialBroker(broker: CredentialBrokerHandle | null, { + drainTimeoutMs = BROKER_DRAIN_TIMEOUT_MS, + pollMs = BROKER_DRAIN_POLL_MS, + gracefulTimeoutMs = BROKER_STOP_GRACE_MS, + forceTimeoutMs = BROKER_STOP_FORCE_MS, + readLedger = readCredentialBrokerLedger, + terminate = (pid: Parameters[0]) => { + if (broker?.container) signalBrokerContainer(broker.container, 'KILL'); + else killTree(pid); + }, + requestStop = (child: CredentialBrokerChild) => { + if (broker?.container) signalBrokerContainer(broker.container, 'TERM'); + else child.kill?.('SIGTERM'); + }, + alive = processAlive, + sleep = wait, + now = Date.now, +}: { drainTimeoutMs?: number; pollMs?: number; gracefulTimeoutMs?: number; forceTimeoutMs?: number; + readLedger?: typeof readCredentialBrokerLedger; terminate?: typeof killTree; + requestStop?: (child: CredentialBrokerChild) => boolean | void; alive?: Alive; + sleep?: (ms: number) => Promise; now?: () => number } = {}): Promise { + if (!broker) return null; + if (broker.finalDiagnostics) return structuredClone(broker.finalLedger ?? null); + let ledger: BrokerLedger | null = null; + const startedAt = now(); + let drainTimedOut = false; + let drainReason: string | null = null; + const errors: BrokerError[] = []; + const errorKeys = new Set(); + const recordError = (type: string, phase: string, error: unknown): void => { + const message = redactDiagnosticText(error instanceof Error ? error.message : error, broker) || 'unknown error'; + const key = `${type}:${phase}:${message}`; + if (errorKeys.has(key)) return; + errorKeys.add(key); + errors.push({ type, phase, message }); + }; + const read = (phase: string, expected: { model: string; maxBudgetUsd: number | null }): BrokerLedger | null => { + try { return readLedger(broker.ledgerPath, expected); } + catch (error) { recordError('ledger-read-error', phase, error); return null; } + }; + let gracefulRequested = false; + let forceRequested = false; + let exited = brokerExited(broker, alive); + const expected = { model: broker.model, maxBudgetUsd: broker.maxBudgetUsd }; + try { + const deadline = now() + drainTimeoutMs; + while (drainReason === null) { + ledger = read('drain', expected) ?? ledger; + if (ledger?.complete === true) { drainReason = 'ledger-complete'; break; } + exited = brokerExited(broker, alive); + if (exited) { drainReason = 'child-exited'; break; } + if (now() >= deadline) { drainTimedOut = true; drainReason = 'timeout'; break; } + await sleep(pollMs); + } + exited = brokerExited(broker, alive); + if (!exited) { + gracefulRequested = true; + try { requestStop(broker.child); } + catch (error) { recordError('termination-error', 'graceful-request', error); } + exited = await waitForBrokerExit(broker, gracefulTimeoutMs, { sleep, now, alive }); + } + if (!exited) { + forceRequested = true; + try { terminate(broker.child.pid); } + catch (error) { recordError('termination-error', 'force-request', error); } + exited = await waitForBrokerExit(broker, forceTimeoutMs, { sleep, now, alive }); + } + if (!exited) recordError('termination-error', 'exit-verification', + new Error('credential broker remained alive after forced termination')); + ledger = read('final', expected) ?? ledger; + } catch (error) { recordError('broker-stop-error', 'shutdown', error); } + finally { + const state = broker.processState ?? {}; + if (exited) { + try { + if (broker.container) brokerDocker(['rm', broker.container.id]); + // Grading can be interrupted before the caller saves its receipt. Keep the + // atomically written spend ledger; remove only the broker's credentials. + for (const name of ['config.json', 'ready.json']) { + rmSync(join(broker.root, name), { force: true }); + } + } + catch (error) { recordError('cleanup-error', 'private-root', error); } + } + broker.finalLedger = ledger; + broker.finalDiagnostics = { + ...(credentialBrokerDiagnostics(broker) as BrokerDiagnostics), + child: { pid: broker.child?.pid ?? null, + exitCode: state.exitCode ?? broker.child?.exitCode ?? null, + signal: state.signal ?? broker.child?.signalCode ?? null, + exitedAt: state.exitedAt ?? null, + stderrTail: state.stderrTail ? redactDiagnosticText(state.stderrTail, broker) : null, + stderrTruncated: state.stderrTruncated === true }, + drain: { timeoutMs: drainTimeoutMs, elapsedMs: Math.max(0, now() - startedAt), + timedOut: drainTimedOut, reason: drainReason, terminationRequested: gracefulRequested }, + termination: { gracefulRequested, forceRequested, exited, gracefulTimeoutMs, forceTimeoutMs }, + ledger: ledger ? structuredClone(ledger) : null, + errors, + }; + } + return ledger; +} diff --git a/tools/stack-bench/container/credential-broker.ts b/tools/stack-bench/container/credential-broker.ts new file mode 100644 index 00000000000..17c8704f34b --- /dev/null +++ b/tools/stack-bench/container/credential-broker.ts @@ -0,0 +1,379 @@ +#!/usr/bin/env node +import { createServer } from 'node:http'; +import type { ClientRequest, IncomingMessage, OutgoingHttpHeaders, ServerResponse } from 'node:http'; +import { request as httpsRequest } from 'node:https'; +import type { RequestOptions } from 'node:https'; +import type { Socket } from 'node:net'; +import { readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { resolve } from 'node:path'; +import { pathToFileURL } from 'node:url'; +import { parseArgs as parseNodeArgs } from 'node:util'; +import type { AddressInfo } from 'node:net'; +import { classifyProviderFailure } from '../src/agents/provider-failure.js'; +import type { ProviderFailure } from '../src/agents/provider-failure.js'; +import { brokerProtocol } from './broker-protocols.js'; + +import { normalizeClaudeUsage } from '../src/evidence/claude-usage-cost.js'; +import type { ClaudeUsage } from '../src/evidence/claude-usage-cost.js'; +import { BROKER_LEDGER_SCHEMA_VERSION, CLAUDE_USAGE_FIELDS, noEstimates, priceNormalizedClaudeUsage, + validateBrokerConfig, + writeCredentialBrokerLedger } from './credential-broker-accounting.js'; +import type { BrokerConfig, EstimateReason, PricingRates } + from './credential-broker-accounting.js'; + +const MAX_REQUEST_BYTES = 32 * 1024 * 1024; +const BROKER_SERVER_CLOSE_GRACE_MS = 1_000; +export type { ClaudeUsage } from '../src/evidence/claude-usage-cost.js'; +type JsonRecord = Record; +export interface BrokerStats { + acceptedRequests: number; + billableRequests: number; + completedBillableRequests: number; + estimatedBillableRequests: number; + spentUsd: number; + reservedUsd: number; +} + +export interface CreatedCredentialBroker { + server: ReturnType; + stats: () => BrokerStats; +} + +type UpstreamRequest = (options: RequestOptions, + callback: (response: IncomingMessage) => void) => ClientRequest; + +const roundUsd = (value: number): number => Number(value.toFixed(6)); +const reserveUsd = (value: number): number => Math.ceil(value * 1e6) / 1e6; + +function fail(message: string): never { + throw new Error(`credential broker: ${message}`); +} + +function clientAuthorized(request: IncomingMessage, sessionToken: string): boolean { + return request.headers.authorization === `Bearer ${sessionToken}` + || request.headers['x-api-key'] === sessionToken; +} + +function requestPath(value: string | undefined): string | null { + try { return new URL(value ?? '', 'http://credential-broker.invalid').pathname; } + catch { return null; } +} + +function rejectRequest(request: IncomingMessage, response: ServerResponse, + status: number, message: string): void { + request.on('error', () => {}); + response.on('error', () => {}); + try { + response.shouldKeepAlive = false; + response.writeHead(status, { 'content-type': 'text/plain', connection: 'close' }); + response.end(message); + } catch { response.destroy(); } + request.resume(); +} + +function requestCostCeiling(bodyBytes: number, maxTokens: number, rates: PricingRates): number { + const inputRate = Math.max(rates.input, rates.cacheRead, rates.cacheWrite5m, rates.cacheWrite1h); + return bodyBytes * inputRate / 1e6 + maxTokens * rates.output / 1e6; +} + +export function createCredentialBroker(configInput: unknown, { + requestUpstream = httpsRequest as UpstreamRequest, + upstream, + maxRequestBytes = MAX_REQUEST_BYTES, +}: { requestUpstream?: UpstreamRequest; + upstream?: { protocol: string; hostname: string; port: number }; + maxRequestBytes?: number } = {}): CreatedCredentialBroker { + const config = validateBrokerConfig(configInput); + const protocol = brokerProtocol(config); + const destination = upstream ?? { protocol: 'https:', hostname: protocol.hostname, port: 443 }; + let acceptedRequests = 0; + let lastResponseRequest = 0; + let providerFailure: ProviderFailure | null = null; + const recordFailure = (request: number, failure: ProviderFailure | null): void => { + if (request >= lastResponseRequest) { lastResponseRequest = request; providerFailure = failure; } + }; + let billableRequests = 0; + let completedBillableRequests = 0; + let estimatedBillableRequests = 0; + const estimatedByReason = noEstimates(); + let spentUsd = 0; + let providerReportedCostUsd = 0; + let providerIntegrityError: string | undefined; + const upstreamProviders = new Set(); + let reservedUsd = 0; + const usageTotals: ClaudeUsage = { input: 0, output: 0, cacheRead: 0, cacheWrite5m: 0, cacheWrite1h: 0 }; + const recordLedger = () => writeCredentialBrokerLedger(config.ledgerPath, { + schemaVersion: BROKER_LEDGER_SCHEMA_VERSION, + ...(config.provider === 'openrouter' ? { provider: config.provider, providerRoute: config.providerRoute, + providerReportedCostUsd: roundUsd(providerReportedCostUsd), upstreamProviders: [...upstreamProviders], + ...(providerIntegrityError ? { providerIntegrityError } : {}) } : {}), + providerFailure, + model: config.model, + maxBudgetUsd: config.maxBudgetUsd ?? null, + acceptedRequests, + billableRequests, + completedBillableRequests, + estimatedBillableRequests, + estimatedByReason, + spentUsd: Number(spentUsd.toFixed(6)), + reservedUsd: Number(reservedUsd.toFixed(6)), + usage: usageTotals, + complete: reservedUsd === 0 && completedBillableRequests === billableRequests, + updatedAt: new Date().toISOString(), + }); + recordLedger(); + const server = createServer((request, response) => { + // A client can disappear while the broker is still draining an upstream + // response. Socket errors must not terminate the broker and strand a paid + // request reservation in the ledger. + request.on('error', () => {}); + request.on('aborted', () => {}); + response.on('error', () => {}); + const responseOpen = (): boolean => !response.destroyed && !response.writableEnded; + const writeHead = (status: number, headers: OutgoingHttpHeaders): void => { + if (!responseOpen() || response.headersSent) return; + try { response.writeHead(status, headers); } + catch { response.destroy(); } + }; + const endResponse = (body?: string | Buffer): void => { + if (!responseOpen()) return; + try { response.end(body); } + catch { response.destroy(); } + }; + if (!clientAuthorized(request, config.sessionToken)) { + rejectRequest(request, response, 401, 'unauthorized'); + return; + } + if (providerIntegrityError) { + rejectRequest(request, response, 502, 'provider accounting or routing validation failed'); + return; + } + const path = requestPath(request.url); + if (request.method !== 'POST' || path === null || !protocol.allowedPaths.has(path)) { + recordFailure(acceptedRequests + 1, { category: 'request', status: 404, code: 'broker-path' }); + recordLedger(); + rejectRequest(request, response, 404, 'not found'); + return; + } + acceptedRequests += 1; + const requestOrdinal = acceptedRequests; + recordLedger(); + + const chunks: Buffer[] = []; + let received = 0; + let tooLarge = false; + request.on('data', (chunk: Buffer) => { + if (tooLarge) return; + received += chunk.length; + if (received > maxRequestBytes) { + tooLarge = true; + recordFailure(requestOrdinal, { category: 'request', status: 413, code: 'broker-body-limit' }); + recordLedger(); + writeHead(413, { 'content-type': 'text/plain' }); + endResponse('request is too large'); + return; + } + chunks.push(chunk); + }); + request.on('end', () => { + if (tooLarge) return; + const body = Buffer.concat(chunks); + let payload: JsonRecord; + try { payload = protocol.parseRequest(body, path); } + catch { + recordFailure(requestOrdinal, { category: 'request', status: 400, code: 'broker-request-invalid' }); + recordLedger(); + writeHead(400, { 'content-type': 'text/plain' }); + endResponse('invalid provider request'); + return; + } + const billable = protocol.billable(path) && config.maxBudgetUsd != null; + const costCeiling = billable + ? reserveUsd(requestCostCeiling(received + (protocol.inputTokenAdjustment?.(payload) ?? 0), protocol.outputLimit(payload), + config.pricingRates as PricingRates)) : 0; + const budget = config.maxBudgetUsd; + if (billable && budget !== null && budget !== undefined + && spentUsd + reservedUsd + costCeiling > budget) { + const measuredSpend = config.provider === 'openrouter' ? providerReportedCostUsd + : priceNormalizedClaudeUsage(usageTotals, config.pricingRates as PricingRates); + recordFailure(requestOrdinal, { category: 'broker-budget', status: 402, code: 'reservation-exceeds-budget', + budget: { maxBudgetUsd: budget, spentUsd, reservedUsd, requestCeilingUsd: costCeiling, + estimatedSpendUsd: roundUsd(Math.max(0, spentUsd - measuredSpend)) } }); + recordLedger(); + writeHead(402, { 'content-type': 'text/plain' }); + endResponse('session budget cannot cover the next request reservation'); + return; + } + if (billable) billableRequests += 1; + reservedUsd = roundUsd(reservedUsd + costCeiling); + recordLedger(); + let billableSettled = !billable; + const settleBillable = ({ usage = null, estimated = null, reportedCost = null }: + { usage?: ClaudeUsage | null; estimated?: EstimateReason | null; reportedCost?: number | null } = {}): void => { + if (billableSettled) return; + billableSettled = true; + reservedUsd = roundUsd(reservedUsd - costCeiling); + completedBillableRequests += 1; + if (estimated) { + estimatedBillableRequests += 1; + estimatedByReason[estimated] += 1; + spentUsd = roundUsd(spentUsd + costCeiling); + } else if (usage) { + spentUsd = roundUsd(spentUsd + (reportedCost ?? priceNormalizedClaudeUsage(usage, config.pricingRates as PricingRates))); + if (reportedCost !== null) { + providerReportedCostUsd = roundUsd(providerReportedCostUsd + reportedCost); + if (reportedCost > costCeiling + 0.000001) { + providerIntegrityError = 'OpenRouter reported cost exceeds the request reservation'; + } + } + for (const field of CLAUDE_USAGE_FIELDS) usageTotals[field] += usage[field]; + } + recordLedger(); + }; + const headers = protocol.headers(request); + for (const name of ['connection', 'keep-alive', 'proxy-connection', 'te', 'trailer', + 'transfer-encoding', 'upgrade']) delete headers[name]; + const forwardedBody = Buffer.from(JSON.stringify(payload)); + headers['content-length'] = String(forwardedBody.length); + const upstreamRequest = requestUpstream({ + protocol: destination.protocol, + hostname: destination.hostname, + port: destination.port, + method: request.method, + path: protocol.upstreamPath(path + new URL(request.url ?? '', 'http://credential-broker.invalid').search), + headers, + }, upstreamResponse => { + writeHead(upstreamResponse.statusCode ?? 502, upstreamResponse.headers); + const responseChunks: Buffer[] = []; + let responseBytes = 0; + upstreamResponse.on('data', (chunk: Buffer) => { + responseBytes += chunk.length; + if (responseBytes <= maxRequestBytes) responseChunks.push(chunk); + if (responseOpen()) { + try { response.write(chunk); } + catch { response.destroy(); } + } + }); + upstreamResponse.on('end', () => { + const status = upstreamResponse.statusCode ?? 502; + recordFailure(requestOrdinal, status >= 200 && status < 300 ? null + : classifyProviderFailure(status, Buffer.concat(responseChunks))); + recordLedger(); + endResponse(); + if (!billable) return; + if ((upstreamResponse.statusCode ?? 502) >= 200 + && (upstreamResponse.statusCode ?? 502) < 300) { + const usage = responseBytes <= maxRequestBytes + ? protocol.responseUsage(Buffer.concat(responseChunks), upstreamResponse.headers['content-encoding']) + : null; + if (!usage) { + if (config.provider === 'openrouter') providerIntegrityError = 'OpenRouter response lacks verified cost and routing metadata'; + recordFailure(requestOrdinal, { category: 'transport', status, code: 'incomplete-response' }); + settleBillable({ estimated: 'no-usage' }); + } + else try { + if (typeof usage.upstream_provider === 'string') upstreamProviders.add(usage.upstream_provider); + settleBillable({ usage: normalizeClaudeUsage(usage), + reportedCost: typeof usage.provider_reported_cost_usd === 'number' ? usage.provider_reported_cost_usd : null }); + } + catch { + recordFailure(requestOrdinal, { category: 'transport', status, code: 'invalid-usage' }); + settleBillable({ estimated: 'no-usage' }); + } + } else { + settleBillable(); + } + }); + const settleAbortedResponse = () => { + recordFailure(requestOrdinal, { category: 'transport', status: null, code: null }); + settleBillable({ estimated: 'response-aborted' }); + if (responseOpen()) response.destroy(); + }; + upstreamResponse.once('aborted', settleAbortedResponse); + upstreamResponse.once('error', settleAbortedResponse); + }); + upstreamRequest.on('error', () => { + recordFailure(requestOrdinal, { category: 'transport', status: null, code: null }); + settleBillable({ estimated: 'upstream-error' }); + writeHead(502, { 'content-type': 'text/plain' }); + endResponse('upstream request failed'); + }); + upstreamRequest.end(forwardedBody); + }); + }); + server.on('clientError', (_error: Error, socket: Socket) => { + socket.on('error', () => {}); + if (socket.writable) socket.end('HTTP/1.1 400 Bad Request\r\nConnection: close\r\n\r\n'); + else socket.destroy(); + }); + return { server, stats: () => ({ acceptedRequests, + billableRequests, completedBillableRequests, estimatedBillableRequests, + estimatedByReason: { ...estimatedByReason }, + spentUsd: Number(spentUsd.toFixed(6)), reservedUsd: Number(reservedUsd.toFixed(6)) }) }; +} + +function parseArgs(argv: string[]): string { + const { values } = parseNodeArgs({ args: argv, options: { config: { type: 'string' } } }); + const configPath = values.config; + if (!configPath || argv.length !== 2) fail('use --config '); + return resolve(configPath); +} + +async function main() { + const configPath = parseArgs(process.argv.slice(2)); + let config: BrokerConfig; + try { config = validateBrokerConfig(JSON.parse(readFileSync(configPath, 'utf8'))); } + finally { rmSync(configPath, { force: true }); } + if (!config.readyPath) fail('readyPath is invalid'); + const { server } = createCredentialBroker(config); + const sockets = new Set(); + server.on('connection', (socket: Socket) => { + sockets.add(socket); + socket.once('close', () => sockets.delete(socket)); + }); + server.on('error', (error: Error) => { + process.stderr.write(`credential broker: ${error.message}\n`); + process.exitCode = 1; + }); + const readyPath = config.readyPath; + server.listen(0, config.listenHost ?? '127.0.0.1', () => { + const address: string | AddressInfo | null = server.address(); + if (!address || typeof address === 'string') fail('listener address is unavailable'); + writeFileSync(readyPath, `${JSON.stringify({ host: address.address, port: address.port })}\n`, + { flag: 'wx', mode: 0o600 }); + }); + let stopping = false; + const stop = () => { + if (stopping) return; + stopping = true; + const force = setTimeout(() => { + for (const socket of sockets) socket.destroy(); + server.closeAllConnections?.(); + process.exit(0); + }, BROKER_SERVER_CLOSE_GRACE_MS); + force.unref(); + server.close(() => { + clearTimeout(force); + process.exit(0); + }); + server.closeIdleConnections?.(); + }; + const parentPid = config.parentPid; + if (parentPid) { + setInterval(() => { + try { process.kill(parentPid, 0); } + catch { stop(); } + }, 1_000).unref(); + } + const expiresAt = config.expiresAt; + if (expiresAt) setTimeout(stop, Math.max(1, expiresAt - Date.now())).unref(); + process.on('SIGINT', stop); + process.on('SIGTERM', stop); +} + +if (process.argv[1] && pathToFileURL(resolve(process.argv[1])).href === import.meta.url) { + main().catch((error: unknown) => { + process.stderr.write(`${error instanceof Error ? error.stack ?? error.message : String(error)}\n`); + process.exit(1); + }); +} diff --git a/tools/stack-bench/container/reconcile-build-container.ts b/tools/stack-bench/container/reconcile-build-container.ts new file mode 100644 index 00000000000..a58fce33aaf --- /dev/null +++ b/tools/stack-bench/container/reconcile-build-container.ts @@ -0,0 +1,77 @@ +import { spawnSync } from 'node:child_process'; +import { createHash } from 'node:crypto'; +import type { SpawnSyncOptionsWithStringEncoding, SpawnSyncReturns } from 'node:child_process'; + +export const BUILD_CONTAINER_CREATION_LABEL = 'com.clockworklabs.stack-bench.creation'; + +export function buildContainerName(lease: { runId: string; + resources: { buildContainer?: { name: string } | null } }): string { + return lease.resources.buildContainer?.name + ?? `sb-${createHash('sha256').update(lease.runId).digest('hex').slice(0, 16)}-build`; +} + +const CONTAINER_ID = /^[a-f0-9]{64}$/i; + +type DockerResult = SpawnSyncReturns; +type DockerExecute = (command: string, args: readonly string[], + options: SpawnSyncOptionsWithStringEncoding) => DockerResult; + +export interface RemoveFailedBuildContainerOptions { + containerName: string; + creationToken: string; + createdId?: string | null; + dockerEnv?: NodeJS.ProcessEnv; + timeoutMs?: number; + execute?: DockerExecute; +} + +export function containerIdFromDockerOutput(output: unknown): string | null { + return String(output ?? '').split(/\r?\n/).map(line => line.trim()) + .find(line => CONTAINER_ID.test(line)) ?? null; +} + +function detail(result: DockerResult): string { + return String(result.stderr || result.stdout || result.error?.message + || `exit ${result.status}`).trim(); +} + +export function removeFailedBuildContainer({ containerName, creationToken, createdId = null, + dockerEnv = process.env, timeoutMs = 120_000, + execute = spawnSync as DockerExecute }: RemoveFailedBuildContainerOptions): { + removed: boolean; absent: boolean; id?: string; +} { + if (typeof containerName !== 'string' || !containerName) { + throw new Error('failed build-container cleanup requires a container name'); + } + if (typeof creationToken !== 'string' || !creationToken) { + throw new Error('failed build-container cleanup requires a creation token'); + } + + let id = containerIdFromDockerOutput(createdId); + if (!id) { + const inspected = execute('docker', ['inspect', '--format', + `{{.Id}} {{index .Config.Labels "${BUILD_CONTAINER_CREATION_LABEL}"}}`, containerName], { + encoding: 'utf8', env: dockerEnv, timeout: timeoutMs, + }); + if (inspected.status !== 0) { + const reason = detail(inspected); + if (/no such (?:object|container)/i.test(reason)) return { removed: false, absent: true }; + throw new Error(`cannot prove cleanup of failed container ${containerName}: ${reason}`); + } + const [inspectedId, label, ...extra] = String(inspected.stdout ?? '').trim().split(/\s+/); + if (!CONTAINER_ID.test(inspectedId ?? '') || label !== creationToken || extra.length > 0) { + throw new Error(`refusing to remove ${containerName}: its creation identity does not match`); + } + id = inspectedId ?? null; + } + + if (!id) throw new Error(`cannot prove cleanup of failed container ${containerName}`); + + const removed = execute('docker', ['rm', '-f', id], { + encoding: 'utf8', env: dockerEnv, timeout: timeoutMs, + }); + if (removed.status !== 0) { + throw new Error(`could not remove failed build container ${id}: ${detail(removed)}`); + } + return { removed: true, absent: false, id }; +} diff --git a/tools/stack-bench/container/recover-build-container.ts b/tools/stack-bench/container/recover-build-container.ts new file mode 100644 index 00000000000..acefebcb228 --- /dev/null +++ b/tools/stack-bench/container/recover-build-container.ts @@ -0,0 +1,77 @@ +import { spawnSync } from 'node:child_process'; +import type { SpawnSyncOptionsWithStringEncoding } from 'node:child_process'; + +import { updateBackendLease } from '../src/runtime/backend-lease.js'; +import type { BackendLease } from '../src/runtime/backend-lease.js'; + +interface StoppedBuildContainer { + id: string; + running: false; +} + +interface LeaseContext { + path: string; + lease: BackendLease; +} + +export interface DockerExecuteResult { + status: number | null; + stdout?: string; + stderr?: string; + error?: Error; +} + +export type DockerExecute = (command: string, args: readonly string[], + options: SpawnSyncOptionsWithStringEncoding) => DockerExecuteResult; + +export interface RecoverStoppedBuildContainerOptions { + existing: StoppedBuildContainer; + containerName: string; + leaseContext: LeaseContext; + backend: string; + dockerEnv?: NodeJS.ProcessEnv; + timeoutMs?: number; + execute?: DockerExecute; +} + +function clearBuildContainerLease(leaseContext: LeaseContext, backend: string, + containerId: string, description: string): LeaseContext { + const lease = updateBackendLease(leaseContext.path, { + token: leaseContext.lease.ownershipToken, backend, runId: leaseContext.lease.runId, + }, next => { + if (next.resources.buildContainer?.id !== containerId) { + throw new Error(`${description} ownership changed before recovery`); + } + next.resources.buildContainer = null; + return next; + }); + return { path: leaseContext.path, lease }; +} + +export function recoverStoppedBuildContainer({ existing, containerName, leaseContext, backend, + dockerEnv = process.env, timeoutMs = 120_000, + execute = spawnSync }: RecoverStoppedBuildContainerOptions): LeaseContext { + const prior = leaseContext?.lease?.resources?.buildContainer ?? null; + if (!existing || existing.running) throw new Error('recovery requires a stopped container'); + if (!prior || prior.name !== containerName || prior.id !== existing.id) { + throw new Error('stopped container does not match the authenticated lease'); + } + const removed = execute('docker', ['rm', existing.id], { + encoding: 'utf8', env: dockerEnv, timeout: timeoutMs, + }); + if (removed.status !== 0) { + throw new Error(`could not remove exact stopped leased container ${existing.id}: ` + + String(removed.stderr || removed.stdout || removed.error?.message || `exit ${removed.status}`).trim()); + } + return clearBuildContainerLease(leaseContext, backend, existing.id, 'stopped container'); +} + +export function clearMissingBuildContainerLease({ containerName, leaseContext, backend }: { + containerName: string; leaseContext: LeaseContext; backend: string; +}): LeaseContext { + const prior = leaseContext?.lease?.resources?.buildContainer ?? null; + if (!prior || prior.name !== containerName) { + throw new Error('missing container does not match the authenticated lease'); + } + return clearBuildContainerLease(leaseContext, backend, prior.id, 'missing container'); +} diff --git a/tools/stack-bench/container/run-build.ts b/tools/stack-bench/container/run-build.ts new file mode 100644 index 00000000000..767660b7e23 --- /dev/null +++ b/tools/stack-bench/container/run-build.ts @@ -0,0 +1,709 @@ +#!/usr/bin/env node +// The build container must not expose Stack Bench source or grading material. +import { spawnSync } from 'node:child_process'; +import { randomBytes } from 'node:crypto'; +import { chmodSync, existsSync, readFileSync, mkdirSync, writeFileSync, unlinkSync } from 'node:fs'; +import { resolve, dirname } from 'node:path'; +import { parseArgs } from 'node:util'; +import { pathToFileURL } from 'node:url'; +import { leaseFromEnv, updateBackendLease } from '../src/runtime/backend-lease.js'; +import { resolveContainerImage } from '../src/runtime/container-image.js'; +import { leasedDatabaseEnvironment, STACK_ADAPTER_REGISTRY } from '../src/stacks/stack-adapters.js'; +import { BUILD_CONTAINER_RESOURCE_LIMITS, DEFAULT_BUILD_IMAGE } + from '../src/composition/product-config.js'; +import { dockerMountArguments } from '../src/runtime/container-mount.js'; +import type { ContainerMount } from '../src/runtime/container-mount.js'; +import { dockerHostGatewayArguments, requireAttemptNetwork, attemptControllerImage, + recordAttemptCreation, ATTEMPT_CREATION_LABEL } from '../src/runtime/docker-network.js'; +import { packageRegistry, packageRegistryEnvironment } from '../src/runtime/package-registry.js'; +import { resolveContainerAuth } from './container-auth.js'; +import { hasRequiredBuildContainerIsolation, inspectBuildContainer, parseCgroupResources, + parsePublishedPorts, waitForBuildContainerReady } + from './build-container-inspection.js'; +import { reconcileCredentialBrokerReceipt } from './credential-broker-accounting.js'; +import { credentialBrokerDiagnostics, startCredentialBroker, stopCredentialBroker } + from './credential-broker-process.js'; +import { clearMissingBuildContainerLease, + recoverStoppedBuildContainer } from './recover-build-container.js'; +import { BUILD_CONTAINER_CREATION_LABEL, buildContainerName, containerIdFromDockerOutput, + removeFailedBuildContainer } from './reconcile-build-container.js'; +import { CODING_SESSION_TIMEOUT_MS } from '../src/agents/coding-session-timeouts.js'; +import { CODING_CONTAINER_AGENT, CODING_CONTAINER_APP_ROOT, CODING_CONTAINER_CONTROL_DIR, + CODING_CONTAINER_PROCESS_IDENTITY, + codingContainerAgentEnvironment, codingContainerTranscriptHandoffCommands, + codingContainerWorkspaceHandoffCommands } + from '../src/runtime/coding-container-policy.js'; +import { PRICING_UNIT, validatePricingAuthority } + from '../src/evidence/pricing-authority.js'; +import { CODING_PROVIDERS, parseCodingProvider } from './coding-providers.js'; +import { validateProviderRoute, validateProviderOutputLimit } from '../src/agents/agent-adapter-contract.js'; +import { REPOSITORY_ROOT } from '../src/package-root.js'; +import type { BuildContainerPlan } from '../src/stacks/stack-agent-operations.js'; + +function errorMessage(error: unknown): string { + return error instanceof Error ? error.message : String(error); +} + +// Trusted lifecycle tests can prepare an unregistered stack through this same +// owner. A supplied plan never permits a coding session or a CLI override. +export async function runBuild(argv = process.argv.slice(2), prepareOnlyPlan?: BuildContainerPlan): Promise { +const { values } = parseArgs({ args: argv, options: { + app: { type: 'string' }, backend: { type: 'string' }, 'prepare-only': { type: 'boolean' }, + provider: { type: 'string' }, image: { type: 'string' }, effort: { type: 'string' }, model: { type: 'string' }, + 'provider-route': { type: 'string' }, + 'max-output-tokens': { type: 'string' }, + 'max-budget-usd': { type: 'string' }, 'pricing-json': { type: 'string' }, + 'resume-session': { type: 'string' }, 'recover-stopped-container': { type: 'boolean' }, + 'completion-marker': { type: 'string' }, ports: { type: 'string' }, +} }); +const prepareOnly = values['prepare-only'] ?? false; +if (prepareOnlyPlan !== undefined && !prepareOnly) { + throw new Error('A supplied build-container plan requires --prepare-only'); +} + +const appDir = values.app; +if (!appDir) { console.error('run-build.js: --app is required'); process.exit(2); } +const backend = values.backend; +if (!backend) { console.error('run-build.js: --backend is required'); process.exit(2); } +let adapter; +try { adapter = prepareOnlyPlan ? null : STACK_ADAPTER_REGISTRY.get(backend); } +catch (error) { console.error(`run-build.js: ${errorMessage(error)}`); process.exit(2); } +const provider = parseCodingProvider(values.provider ?? 'anthropic'); +const providerRoute = validateProviderRoute(provider, values['provider-route']); +const maxOutputTokens = validateProviderOutputLimit(provider, + values['max-output-tokens'] === undefined ? undefined : Number(values['max-output-tokens'])); +const codingProvider = CODING_PROVIDERS[provider]; +const DOCKER_TIMEOUT_MS = 120_000; +const DOCKER_PROBE_TIMEOUT_MS = 10_000; +const { uid: AGENT_UID, gid: AGENT_GID, home: AGENT_HOME } = CODING_CONTAINER_AGENT; +const CONTROLLER_GID = process.getgid?.() ?? 0; +const AGENT_ENVIRONMENT = codingContainerAgentEnvironment(); +const CONTROL_DIR = CODING_CONTAINER_CONTROL_DIR; +const REQUIRED_CAPABILITIES = Object.freeze([ + 'CHOWN', 'DAC_OVERRIDE', 'FOWNER', 'KILL', 'SETGID', 'SETUID', +]); +const REQUIRED_TMPFS = Object.freeze({ + '/tmp': 'rw,nosuid,nodev,mode=1777', + [AGENT_HOME]: `rw,nosuid,nodev,uid=${AGENT_UID},gid=${AGENT_GID},mode=0700`, + [`${AGENT_HOME}/.claude`]: `rw,nosuid,nodev,uid=${AGENT_UID},gid=${AGENT_GID},mode=0700`, + '/deps': 'rw,exec,nosuid,nodev,mode=0755', + [CONTROL_DIR]: 'rw,nosuid,nodev,mode=0700', +}); + +const REPO = REPOSITORY_ROOT; +const imageReference = values.image ?? DEFAULT_BUILD_IMAGE; +let imageIdentity; +try { imageIdentity = resolveContainerImage(imageReference); } +catch (error) { + console.error(`run-build.js: cannot resolve image ${imageReference}: ${errorMessage(error)}`); + process.exit(2); +} +const image = imageIdentity.id; +const effort = values.effort ?? ''; +const model = values.model ?? ''; +if (!prepareOnly && (!effort || !model)) { + console.error('run-build.js: --effort and --model are required'); + process.exit(2); +} +const maxBudgetUsd = values['max-budget-usd'] ?? null; +if (!prepareOnly && codingProvider.requiresBudget && maxBudgetUsd === null) { + throw new Error('this coding provider requires --max-budget-usd and explicit pricing'); +} +if (maxBudgetUsd !== null && (!Number.isFinite(Number(maxBudgetUsd)) || Number(maxBudgetUsd) <= 0)) { + console.error('run-build.js: --max-budget-usd must be a positive number'); + process.exit(2); +} +let pricing = null; +try { + const supplied = values['pricing-json'] ?? null; + if (supplied !== null) { + pricing = validatePricingAuthority(JSON.parse(supplied), { at: '--pricing-json' }); + } else if (maxBudgetUsd !== null) { + const rates = codingProvider.rates(model); + if (!rates) throw new Error(`no default pricing is recorded for model ${model}`); + pricing = validatePricingAuthority({ unit: PRICING_UNIT, rates }, + { at: 'default pricing' }); + } +} catch (error) { + console.error(`run-build.js: ${errorMessage(error)}`); + process.exit(2); +} +const resumeSession = values['resume-session'] ?? null; +if (resumeSession !== null + && !/^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(resumeSession)) { + console.error('run-build.js: --resume-session must be a UUID'); + process.exit(2); +} +const recoverStoppedContainer = values['recover-stopped-container'] ?? false; +const completionMarker = values['completion-marker'] ?? null; +if (!prepareOnly && !/^[A-Z][A-Z0-9_]*$/.test(completionMarker ?? '')) { + console.error('run-build.js: --completion-marker must be an uppercase marker'); + process.exit(2); +} +let ports: string[] = []; +try { ports = parsePublishedPorts(values.ports); } +catch (error) { console.error(`run-build.js: ${errorMessage(error)}`); process.exit(2); } + +const containerPlan = prepareOnlyPlan ?? adapter!.buildContainer.plan({ + repo: REPO, appDir, env: process.env, +}); + +// Auth is resolved in the controller. A short-lived broker forwards model API +// requests later. The coding container never receives the long-lived provider +// credential or a credential file. +const apiKey = process.env.STACK_BENCH_AGENT_API_KEY + ?? process.env[codingProvider.apiKeyEnvironment] ?? ''; +let auth = null; +if (!prepareOnly) { + try { auth = resolveContainerAuth({ provider, apiKey, env: process.env, credentialsPath: codingProvider.credentialPath }); } + catch (error) { console.error(`run-build.js: ${errorMessage(error)}`); process.exit(2); } +} + +// Persist this run's transcript without exposing other local sessions. +const projects = prepareOnly ? null : codingProvider.projects(appDir); +const containerTranscripts = codingProvider.containerTranscripts; +function ensureAgentDirectory(directory: string): void { + mkdirSync(directory, { recursive: true, + mode: process.env.STACK_BENCH_APPLIANCE === '1' ? 0o700 : 0o777 }); + if (process.env.STACK_BENCH_APPLIANCE !== '1') chmodSync(directory, 0o777); +} + +ensureAgentDirectory(appDir); +if (projects) ensureAgentDirectory(projects); +for (const directory of containerPlan.ensureDirectories) ensureAgentDirectory(directory); + +const dockerEnv: NodeJS.ProcessEnv = { ...process.env, MSYS_NO_PATHCONV: '1' }; + +function resolveNetworkMode(): string { + if (process.env.STACK_BENCH_APPLIANCE !== '1') return 'bridge'; + return requireAttemptNetwork(leaseFromEnv(process.env, { backend, active: true }).lease); +} + +let expectedNetworkMode: string; +try { expectedNetworkMode = resolveNetworkMode(); } +catch (error) { + console.error(`run-build.js: ${errorMessage(error)}`); + process.exit(2); +} + +const inspectContainer = (name: string) => inspectBuildContainer(name, + { env: dockerEnv, timeoutMs: DOCKER_TIMEOUT_MS }); + +const hasRequiredIsolation = (container: NonNullable>, + expectedMounts: ContainerMount[]): boolean => hasRequiredBuildContainerIsolation(container, { + expectedMounts, + requiredTmpfs: REQUIRED_TMPFS, + requiredCapabilities: REQUIRED_CAPABILITIES, + pidsLimit: BUILD_CONTAINER_RESOURCE_LIMITS.pids, + cpuCount: BUILD_CONTAINER_RESOURCE_LIMITS.cpuCount, + memoryBytes: BUILD_CONTAINER_RESOURCE_LIMITS.memoryBytes, + memorySwapBytes: BUILD_CONTAINER_RESOURCE_LIMITS.memorySwapBytes, + image, +}); + +const expectedMounts: ContainerMount[] = [ + { kind: 'bind' as const, source: resolve(appDir), target: CODING_CONTAINER_APP_ROOT, readOnly: false }, + ...(projects ? [{ kind: 'bind' as const, source: projects, + target: containerTranscripts, readOnly: false }] : []), + ...containerPlan.mounts, +]; + +// Only the lease's immutable container id grants reuse or deletion authority. +let leaseContext; +try { leaseContext = leaseFromEnv(process.env, { backend, active: true }); } +catch (error) { + console.error(`run-build.js: an authenticated active backend lease is required: ${errorMessage(error)}`); + process.exit(3); +} + +// App directories can share a parent. Container identity belongs to the lease. +const containerName = buildContainerName(leaseContext.lease); +let existing = inspectContainer(containerName); +const priorContainer = leaseContext.lease.resources.buildContainer ?? null; +if (existing) { + if (!priorContainer) { + console.error(`run-build.js: refusing to adopt existing unleased container ${containerName}`); + process.exit(3); + } + if (priorContainer.name !== containerName || priorContainer.id !== existing.id) { + console.error(`run-build.js: existing container ${containerName}/${existing.id} does not match lease ` + + `${priorContainer.name}/${priorContainer.id}`); + process.exit(3); + } + if (!existing.running) { + if (!recoverStoppedContainer) { + console.error(`run-build.js: leased container ${containerName} stopped unexpectedly; refusing to replace it`); + process.exit(3); + } + try { + leaseContext = recoverStoppedBuildContainer({ existing: { ...existing, running: false }, containerName, leaseContext, backend, + dockerEnv, timeoutMs: DOCKER_TIMEOUT_MS }); + existing = null; + } catch (error) { + console.error(`run-build.js: could not recover stopped container: ${errorMessage(error)}`); + process.exit(3); + } + } + if (existing && existing.networkMode !== expectedNetworkMode) { + console.error(`run-build.js: leased container ${containerName} uses network ${existing.networkMode}, ` + + `expected ${expectedNetworkMode}`); + process.exit(3); + } + if (existing?.unsafeCredentialExposure) { + console.error(`run-build.js: leased container ${containerName} was created with a provider credential; ` + + 'reconcile the run and start it with the isolated credential broker'); + process.exit(3); + } + if (existing && !hasRequiredIsolation(existing, expectedMounts)) { + console.error(`run-build.js: leased container ${containerName} does not have the required isolation`); + process.exit(3); + } +} else if (priorContainer) { + const leasedById = inspectContainer(priorContainer.id); + if (leasedById) { + console.error(`run-build.js: leased container ${priorContainer.id} still exists under an unexpected name`); + process.exit(3); + } + if (!recoverStoppedContainer) { + console.error(`run-build.js: leased container ${priorContainer.name}/${priorContainer.id} is missing`); + process.exit(3); + } + try { + leaseContext = clearMissingBuildContainerLease({ containerName, leaseContext, backend }); + } catch (error) { + console.error(`run-build.js: could not recover missing container lease: ${errorMessage(error)}`); + process.exit(3); + } +} + +// Create it if this is the first round of the run; reuse it for every round +// after, so a repair finds the app, its node_modules and its servers exactly +// where the build round left them. +let containerInspection = existing; +if (!existing) { + const creationToken = randomBytes(16).toString('hex'); + if (leaseContext.lease.resources.network) updateBackendLease(leaseContext.path, + { token: leaseContext.lease.ownershipToken }, next => { + (next.resources.creationIntents ??= {}).build = { name: containerName, creationToken }; + return next; + }); + const create = [ + 'create', '--init', '--name', containerName, + '--label', `${BUILD_CONTAINER_CREATION_LABEL}=${creationToken}`, + '--label', `${ATTEMPT_CREATION_LABEL}=${creationToken}`, + '--cap-drop', 'ALL', '--security-opt', 'no-new-privileges:true', + '--pids-limit', String(BUILD_CONTAINER_RESOURCE_LIMITS.pids), + '--cpus', String(BUILD_CONTAINER_RESOURCE_LIMITS.cpuCount), + '--memory', String(BUILD_CONTAINER_RESOURCE_LIMITS.memoryBytes), + '--memory-swap', String(BUILD_CONTAINER_RESOURCE_LIMITS.memorySwapBytes), + // The agent may write the app, its own home directory, and temporary files. + // It must not replace system binaries or libraries used by later grading. + '--read-only', + '-v', `${resolve(appDir)}:${CODING_CONTAINER_APP_ROOT}`, + ]; + for (const capability of REQUIRED_CAPABILITIES) create.push('--cap-add', capability); + for (const [path, options] of Object.entries(REQUIRED_TMPFS)) { + create.push('--tmpfs', `${path}:${options}`); + } + create.push('--network', expectedNetworkMode); + create.push(...dockerHostGatewayArguments(expectedNetworkMode)); + if (projects) create.push('-v', `${projects}:${containerTranscripts}`); + // The selected adapter owns every stack-specific mount. Giving a treatment + // another stack's artifacts would violate the "only artifacts under test" + // boundary. + for (const requiredPath of containerPlan.requiredPaths) { + if (!existsSync(requiredPath)) { + console.error(`run-build.js: ${backend} container artifact is missing: ${requiredPath}`); + process.exit(2); + } + } + for (const mount of containerPlan.mounts) { + try { create.push(...dockerMountArguments(mount)); } + catch (error) { + console.error(`run-build.js: ${backend} adapter returned an invalid container mount: ${errorMessage(error)}`); + process.exit(2); + } + } + + // Publish the track's ports for the host grader. + if (expectedNetworkMode === 'bridge') for (const p of ports) create.push('-p', `127.0.0.1:${p}:${p}`); + // Container-level, so the agent's installs and every later exec share it. + for (const [key, value] of Object.entries( + packageRegistryEnvironment(packageRegistry(), expectedNetworkMode, leaseContext.lease.resources.network))) { + create.push('-e', `${key}=${value}`); + } + + // `--init` gives the container a real PID 1. Without it the dev servers the + // build leaves behind are reparented to `sleep`, which never reaps them. + const init = 'export HOME=/tmp npm_config_cache=/tmp/npm-cache; ' + + containerPlan.init; + create.push('-w', CODING_CONTAINER_APP_ROOT, image, 'sh', '-c', init); + + const made = spawnSync('docker', create, { + encoding: 'utf8', env: dockerEnv, timeout: DOCKER_TIMEOUT_MS, + }); + if (made.status !== 0) { + console.error(`run-build.js: could not create ${containerName}`); + console.error(made.stderr || made.stdout || made.error?.message || ''); + try { + removeFailedBuildContainer({ containerName, creationToken, + createdId: containerIdFromDockerOutput(made.stdout), dockerEnv, + timeoutMs: DOCKER_TIMEOUT_MS }); + } catch (cleanupError) { + console.error(`run-build.js: ${errorMessage(cleanupError)}`); + process.exit(3); + } + process.exit(2); + } + + const createdId = containerIdFromDockerOutput(made.stdout); + try { containerInspection = inspectContainer(containerName); } + catch (error) { + console.error(`run-build.js: cannot inspect ${containerName}: ${errorMessage(error)}`); + } + if (!containerInspection) { + try { + removeFailedBuildContainer({ containerName, creationToken, createdId, dockerEnv, + timeoutMs: DOCKER_TIMEOUT_MS }); + } catch (cleanupError) { + console.error(`run-build.js: ${errorMessage(cleanupError)}`); + process.exit(3); + } + console.error(`run-build.js: cannot inspect ${containerName}`); + process.exit(2); + } + if (containerInspection.unsafeCredentialExposure + || !hasRequiredIsolation(containerInspection, expectedMounts)) { + try { + removeFailedBuildContainer({ containerName, creationToken, createdId, dockerEnv, + timeoutMs: DOCKER_TIMEOUT_MS }); + } catch (cleanupError) { + console.error(`run-build.js: ${errorMessage(cleanupError)}`); + process.exit(3); + } + console.error(`run-build.js: created container ${containerName} does not have the required isolation`); + process.exit(2); + } +} + +if (!containerInspection) { + console.error(`run-build.js: cannot inspect ${containerName}`); + process.exit(2); +} +const { id: containerId, image: containerImage } = containerInspection; +try { + const { path, lease } = leaseContext; + const prior = lease.resources.buildContainer; + if (prior && (prior.name !== containerName || prior.id !== containerId)) { + throw new Error(`running container ${containerName}/${containerId} does not match lease ` + + `${prior.name}/${prior.id}`); + } + updateBackendLease(path, { token: lease.ownershipToken, backend, runId: lease.runId }, next => { + next.resources.buildContainer = { + name: containerName, id: containerId, image: containerImage, owned: true, running: existing !== null, + networkMode: expectedNetworkMode, + resourceLimits: structuredClone(BUILD_CONTAINER_RESOURCE_LIMITS), + }; + return next; + }); +} catch (error) { + // Creation succeeded but ownership recording did not. Remove only the exact + // id created by this invocation; leaving an unleased container is not safe. + if (!existing) { + spawnSync('docker', ['rm', '-f', containerId], { + stdio: 'ignore', env: dockerEnv, timeout: DOCKER_TIMEOUT_MS, + }); + } + console.error(`run-build.js: ${errorMessage(error)}`); + process.exit(3); +} + +if (!existing) { + const started = spawnSync('docker', ['start', containerId], { + encoding: 'utf8', env: dockerEnv, timeout: DOCKER_TIMEOUT_MS, + }); + if (started.status !== 0) { + console.error(`run-build.js: could not start leased container ${containerName}/${containerId}`); + console.error(started.stderr || started.stdout || started.error?.message || ''); + process.exit(2); + } + try { + const { path, lease } = leaseContext; + updateBackendLease(path, { token: lease.ownershipToken, backend, runId: lease.runId }, next => { + if (next.resources.buildContainer?.id !== containerId) { + throw new Error(`leased container changed before start: expected ${containerId}`); + } + next.resources.buildContainer.running = true; + return next; + }); + } catch (error) { + console.error(`run-build.js: started container ownership could not be recorded: ${errorMessage(error)}`); + process.exit(3); + } +} + +if (containerPlan.readyFile) { + // Wait until SDK staging finishes before starting the paid session. + try { + waitForBuildContainerReady(containerId, containerPlan.readyFile, + containerPlan.readyDescription ?? `${backend} setup`, { env: dockerEnv }); + } catch (error) { + console.error(`run-build.js: ${errorMessage(error)}`); + process.exit(2); + } +} + +if (process.env.STACK_BENCH_APPLIANCE === '1') { + const writableTargets = [AGENT_HOME, + ...expectedMounts.filter(mount => !mount.readOnly).map(mount => mount.target)]; + for (const [command, commandArgs] of [ + ['chown', ['-R', `${AGENT_UID}:${CONTROLLER_GID}`, '--', ...writableTargets]], + ['chmod', ['-R', 'u+rwX,g+rwX,o-rwx', '--', ...writableTargets]], + ] as const) { + const permissions = spawnSync('docker', ['exec', containerName, command, ...commandArgs], { + encoding: 'utf8', env: dockerEnv, timeout: DOCKER_PROBE_TIMEOUT_MS, + }); + if (permissions.status !== 0) { + console.error(`run-build.js: could not secure writable paths in ${containerName}`); + console.error(permissions.stderr || permissions.stdout || permissions.error?.message || ''); + process.exit(2); + } + } +} + +// A nested transcript mount makes Docker create its parent directories as +// root. Confirm that the coding runner can create its private session state before a +// provider request can spend money. +const homeProbe = spawnSync('docker', [ + 'exec', '--user', `${AGENT_UID}:${AGENT_GID}`, '-e', `HOME=${AGENT_HOME}`, + containerName, 'sh', '-c', + 'umask 077; mkdir -p "$1" && test -w "$1"', 'home-probe', dirname(containerTranscripts), +], { encoding: 'utf8', env: dockerEnv, timeout: DOCKER_PROBE_TIMEOUT_MS }); +if (homeProbe.status !== 0) { + console.error(`run-build.js: agent home is not writable in ${containerName}`); + console.error(homeProbe.stderr || homeProbe.stdout || homeProbe.error?.message || ''); + process.exit(2); +} + +// Docker bind sources must be the same filesystem the controller audits. +if (projects) { + const probe = `.mount-probe-${randomBytes(12).toString('hex')}`; + const expected = randomBytes(24).toString('hex'); + const path = resolve(projects, probe); + writeFileSync(path, expected, { mode: 0o644 }); + try { + const result = spawnSync('docker', ['exec', '--user', `${AGENT_UID}:${AGENT_GID}`, + containerName, 'cat', `${containerTranscripts}/${probe}`], + { encoding: 'utf8', env: dockerEnv, timeout: DOCKER_PROBE_TIMEOUT_MS }); + if (result.status !== 0 || result.stdout !== expected) { + throw new Error('Transcript mount is not shared with the controller. Use the shared controller HOME before starting a session.'); + } + } finally { unlinkSync(path); } +} + +if (prepareOnly) { + process.stdout.write(`${JSON.stringify({ containerName, + identity: `${containerId} ${containerImage}`, + networkMode: expectedNetworkMode })}\n`); + return; +} + +const args = ['exec', '-i', '--user', `${AGENT_UID}:${AGENT_GID}`, '-w', CODING_CONTAINER_APP_ROOT]; + +args.push('-e', `HOME=${AGENT_ENVIRONMENT.HOME}`, '-e', `USER=${AGENT_ENVIRONMENT.USER}`); +const leasedEnvironment = leasedDatabaseEnvironment(adapter!, { + database: leaseContext.lease.resources.database, networkMode: expectedNetworkMode, lease: leaseContext.lease, +}); +for (const [key, value] of Object.entries(leasedEnvironment)) args.push('-e', `${key}=${value}`); +const dockerExecEnv: NodeJS.ProcessEnv = { ...process.env, MSYS_NO_PATHCONV: '1' }; +if (!projects) throw new Error('transcript directory is unavailable'); +// Forward only benchmark-owned environment settings. +if (provider === 'anthropic' && process.env.MAX_THINKING_TOKENS) { + args.push('-e', `MAX_THINKING_TOKENS=${process.env.MAX_THINKING_TOKENS}`); +} + +// Record the exact remote PID. Killing the local `docker exec` client does not +// guarantee that the coding runner stops inside the long-lived build container. +const invocationToken = randomBytes(16).toString('hex'); +const processRecord = `${CODING_CONTAINER_PROCESS_IDENTITY.recordPrefix}${invocationToken}.pid`; +const sessionWrapper = 'umask 022; record="$1"; shift; ' + + 'start="$(awk \'{print $22}\' /proc/$$/stat)" || exit 1; ' + + 'printf \'%s %s\\n\' "$$" "$start" > "$record"; exec "$@"'; + +if (!auth) throw new Error('container authentication is unavailable'); +let credentialBroker: Awaited> | null = null; +try { + const docker = leaseContext.lease.resources.network ? (() => { + const intent = recordAttemptCreation(leaseContext.path, leaseContext.lease, 'broker'); + return { imageId: attemptControllerImage(), + networkContainerId: leaseContext.lease.resources.network!.namespaceContainerId!, + ...intent, privateDirectory: dirname(leaseContext.path), + onCreated: (container: import('./credential-broker-process.js').CredentialBrokerContainer) => { + updateBackendLease(leaseContext.path, { token: leaseContext.lease.ownershipToken }, next => { + next.resources.brokerContainer = container; return next; + }); + } }; + })() : undefined; + credentialBroker = await startCredentialBroker(auth, + { networkMode: expectedNetworkMode, deadlineMs: CODING_SESSION_TIMEOUT_MS, model, + providerRoute, maxOutputTokens, + docker, + maxBudgetUsd: maxBudgetUsd === null ? null : Number(maxBudgetUsd), + pricingRates: maxBudgetUsd === null ? null : pricing!.rates }); +} catch (error) { + console.error(`run-build.js: ${errorMessage(error)}`); + process.exit(2); +} +if (!credentialBroker) throw new Error('credential broker is unavailable'); +const tokenEnvironment = codingProvider.tokenEnvironment; +dockerExecEnv[tokenEnvironment] = credentialBroker.sessionToken; +args.push('-e', tokenEnvironment, ...codingProvider.environment(credentialBroker.baseUrl).flatMap(value => ['-e', value]), + containerName, 'sh', '-c', sessionWrapper, CODING_CONTAINER_PROCESS_IDENTITY.sessionLabel, + processRecord, + codingProvider.executable, ...codingProvider.args({ model, effort, baseUrl: credentialBroker.baseUrl, + resumeSession, maxBudgetUsd })); + +// MSYS_NO_PATHCONV: Git Bash rewrites container-side paths like /app into +// Windows paths (C:/Program Files/Git/app) and every mount silently lands +// somewhere wrong. +const promptInput = process.stdin.isTTY ? '' : readFileSync(0, 'utf8'); +function signalSession(signal: 'TERM' | 'KILL') { + const script = 'record="$1"; signal="$2"; test -r "$record" || exit 4; ' + + 'read -r pid expected < "$record"; ' + + 'current="$(awk \'{print $22}\' "/proc/$pid/stat" 2>/dev/null)" || exit 5; ' + + 'test "$current" = "$expected" || exit 3; kill "-$signal" "$pid"'; + return spawnSync('docker', ['exec', containerName, 'sh', '-c', script, + CODING_CONTAINER_PROCESS_IDENTITY.stopLabel, processRecord, signal], { + encoding: 'utf8', env: dockerExecEnv, timeout: DOCKER_PROBE_TIMEOUT_MS, + }); +} +function terminateSession(child: { kill(signal?: NodeJS.Signals): boolean }): void { + const term = signalSession('TERM'); + if (term.status !== 0) child.kill('SIGTERM'); + const force = setTimeout(() => { + signalSession('KILL'); + child.kill('SIGKILL'); + }, 5_000); + force.unref(); +} + +let res: Awaited> | undefined; +let sessionError: unknown = null; +let brokerLedger = null; +let brokerDiagnostics = null; +const cleanupErrors: string[] = []; +const runCleanupCommand = (description: string, command: readonly string[]): void => { + const result = spawnSync('docker', ['exec', containerName, ...command], { + encoding: 'utf8', env: dockerExecEnv, timeout: DOCKER_PROBE_TIMEOUT_MS, + }); + if (result.status !== 0) cleanupErrors.push(`${description}: ${String(result.stderr || result.stdout + || result.error?.message || `exit ${result.status}`).trim()}`); +}; +try { + res = await codingProvider.run({ command: 'docker', args, input: promptInput, + env: dockerExecEnv, timeoutMs: CODING_SESSION_TIMEOUT_MS, terminate: terminateSession, + projects, containerId, marker: completionMarker as string, model, + pricingRates: pricing?.rates ?? null, resumeSession }); +} catch (error) { + sessionError = error; +} finally { + brokerLedger = await stopCredentialBroker(credentialBroker); + brokerDiagnostics = credentialBrokerDiagnostics(credentialBroker); + if (credentialBroker.container && brokerDiagnostics?.termination?.exited + && !brokerDiagnostics.errors.some(error => error.type === 'cleanup-error')) { + updateBackendLease(leaseContext.path, { token: leaseContext.lease.ownershipToken }, next => { + delete next.resources.brokerContainer; + delete next.resources.creationIntents?.broker; + return next; + }); + } + for (const command of codingContainerTranscriptHandoffCommands(CONTROLLER_GID, containerTranscripts)) { + runCleanupCommand('transcript handoff', command); + } + const handoff = process.env.STACK_BENCH_APPLIANCE === '1' + ? codingContainerWorkspaceHandoffCommands(CONTROLLER_GID) + : [['chmod', '-R', 'a+rwX', CODING_CONTAINER_APP_ROOT]]; + for (const command of handoff) runCleanupCommand('workspace handoff', command); + runCleanupCommand('process-record cleanup', ['rm', '-f', processRecord]); +} + +if (sessionError) { + if (cleanupErrors.length) { + throw new AggregateError([sessionError, ...cleanupErrors.map(message => new Error(message))], + 'coding session and container cleanup failed'); + } + throw sessionError; +} +if (!res) throw new Error('coding session returned no process result'); +if (cleanupErrors.length) { + res.status = res.status === 0 ? 3 : res.status ?? 3; + res.stderr = `${res.stderr ?? ''}${res.stderr ? '\n' : ''}` + + `run-build.js: container cleanup failed: ${cleanupErrors.join('; ')}\n`; +} + +const cliResult = codingProvider.result(String(res.stdout ?? '').trim(), appDir, invocationToken); +if (cliResult) cliResult.stack_bench_auth_mode = auth.mode; +const memory = spawnSync('docker', ['exec', containerName, 'sh', '-c', + 'for f in memory.events memory.current memory.peak memory.max pids.current pids.peak pids.max pids.events; do ' + + 'p="/sys/fs/cgroup/$f"; if test -r "$p"; then echo "[$f]"; cat "$p"; fi; done'], { + encoding: 'utf8', env: dockerExecEnv, timeout: DOCKER_PROBE_TIMEOUT_MS, +}); +const resources = { + ...(memory.status === 0 ? parseCgroupResources(memory.stdout) + : { buildContainerMemory: null, buildContainerPids: null }), + memoryProbeError: memory.status === 0 ? null + : memory.stderr?.trim() || (memory.error instanceof Error ? memory.error.message : null) + || `exit ${memory.status}`, +}; +if (maxBudgetUsd !== null) { + const reconciled = reconcileCredentialBrokerReceipt({ + ledger: brokerLedger, + provider, + cliResult, + model, + maxBudgetUsd: Number(maxBudgetUsd), + pricingRates: pricing!.rates, + brokerDiagnostics, + }); + reconciled.result.stack_bench_resources = resources; + res.stdout = `${JSON.stringify(reconciled.result)}\n`; + if (!reconciled.ok) { + res.status = res.status === 0 ? 3 : res.status ?? 3; + res.stderr = `${res.stderr ?? ''}${res.stderr ? '\n' : ''}` + + `run-build.js: ${reconciled.receipt.error}\n`; + } +} else if (cliResult && typeof cliResult === 'object' && !Array.isArray(cliResult)) { + cliResult.stack_bench_credential_broker = brokerDiagnostics; + cliResult.stack_bench_resources = resources; + res.stdout = `${JSON.stringify(cliResult)}\n`; +} + +if ((res.status ?? 1) !== 0) { + const state = spawnSync('docker', ['inspect', '--format', '{{json .State}}', containerName], { + encoding: 'utf8', env: dockerExecEnv, timeout: DOCKER_PROBE_TIMEOUT_MS, + }); + let containerState = null; + try { containerState = JSON.parse(state.stdout?.trim() || 'null'); } catch { /* retain raw text below */ } + const diagnostic = { + schemaVersion: 1, + kind: 'coding-process-exit', + status: res.status ?? null, + signal: res.signal ?? null, + error: res.error instanceof Error ? res.error.message : null, + container: containerState ?? { inspectError: state.stderr?.trim() + || (state.error instanceof Error ? state.error.message : null) }, + cgroupMemory: memory.stdout?.trim() || null, + cgroupProbeError: memory.status === 0 ? null + : memory.stderr?.trim() || (memory.error instanceof Error ? memory.error.message : null) + || `exit ${memory.status}`, + }; + process.stderr.write(`STACK_BENCH_CODING_PROCESS_DIAGNOSTIC ${JSON.stringify(diagnostic)}\n`); +} + +if (res.stdout) process.stdout.write(res.stdout); +if (res.stderr) process.stderr.write(res.stderr); +if (res.error) process.stderr.write(`run-build.js: coding session failed: ${errorMessage(res.error)}\n`); +process.exit(res.status ?? 1); +} + +if (process.argv[1] && pathToFileURL(resolve(process.argv[1])).href === import.meta.url) await runBuild(); diff --git a/tools/stack-bench/container/spacetime-dev.ts b/tools/stack-bench/container/spacetime-dev.ts new file mode 100644 index 00000000000..161dee0b0a2 --- /dev/null +++ b/tools/stack-bench/container/spacetime-dev.ts @@ -0,0 +1,94 @@ +// Standalone development process command; Node built-ins only. +import { spawn } from 'node:child_process'; +import { existsSync, readFileSync, writeFileSync, openSync, closeSync, rmSync, realpathSync } from 'node:fs'; +import { resolve, relative, isAbsolute, dirname, join } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { setTimeout as delay } from 'node:timers/promises'; + +function marker(pid: number): string | null { + try { + const stat = readFileSync(`/proc/${pid}/stat`, 'utf8'); + const fields = stat.slice(stat.lastIndexOf(')') + 2).split(' '); + return fields[0] === 'Z' ? null : fields[19] ?? null; + } catch { return null; } +} + +export function validateProject(root: string, server: string, database: string): void { + const read = (name: string) => JSON.parse(readFileSync(join(root, name), 'utf8')); + const config = { ...read('spacetime.json'), + ...(existsSync(join(root, 'spacetime.local.json')) ? read('spacetime.local.json') : {}) }; + if (config.server !== server || config.database !== database || config.publish !== undefined) { + throw new Error('Configure one database using the supplied server URL and database name.'); + } + const contained = (path: unknown): string => { + if (typeof path !== 'string' || !path.trim()) throw new Error('Configure module-path and generate out-dir.'); + const full = resolve(root, path); + let existing = full; + while (!existsSync(existing)) existing = dirname(existing); + for (const candidate of [full, realpathSync(existing)]) { + const rel = relative(realpathSync(root), candidate); + if (isAbsolute(rel) || rel === '..' || rel.startsWith('../')) throw new Error('Project paths must stay inside the application directory.'); + } + return full; + }; + if (!existsSync(contained(config['module-path']))) throw new Error('Create the module directory before starting development.'); + if (!Array.isArray(config.generate) || !config.generate.length) throw new Error('Configure at least one generate target.'); + for (const target of config.generate) { + if (!target || target.language !== 'typescript') throw new Error('Configure TypeScript generate targets.'); + contained(target['out-dir']); + if (target['module-path'] !== undefined) contained(target['module-path']); + if ((target.server !== undefined && target.server !== server) + || (target.database !== undefined && target.database !== database)) throw new Error('Generate targets must use the supplied database.'); + } +} + +// Calls are serialized by the installed flock wrapper. The detached watcher is +// still owned by the agent UID and the existing container teardown stops it. +export async function main(args: string[]): Promise { + const [root, state, cli, server, database, command = 'status', ...extra] = args; + if (!root || !state || !cli || !server || !database || extra.length + || !['start', 'status', 'stop'].includes(command)) throw new Error('Usage: spacetime-dev start|status|stop'); + const record = join(state, 'process.json'), ready = join(state, 'ready'), log = join(state, 'watcher.log'); + const previous = existsSync(record) ? JSON.parse(readFileSync(record, 'utf8')) : null; + const alive = () => previous && Number.isSafeInteger(previous.pid) && previous.pid > 1 + && typeof previous.marker === 'string' && marker(previous.pid) === previous.marker; + if (command === 'stop') { + if (alive()) { + // Stop the whole build group together, including a compiler child. + process.kill(-previous.pid, 'SIGKILL'); + for (let i = 0; i < 50 && alive(); i++) await delay(100); + if (alive()) throw new Error(`Watcher did not stop. Read ${log}`); + } + rmSync(record, { force: true }); rmSync(ready, { force: true }); + console.log(`Stopped. Log: ${log}`); return; + } + if (alive()) { + console.log(`${existsSync(ready) ? 'Running; initial publish and bindings completed' : 'Starting; initial publish not yet confirmed'}. Log: ${log}`); + return; + } + if (command === 'status') { console.log(`Not running. Log: ${log}`); return; } + validateProject(root, server, database); + rmSync(ready, { force: true }); + const output = openSync(log, 'w', 0o600); + const child = spawn(cli, ['dev', '--yes', '--delete-data=never', '--server-only', '--ready-file', ready], + { cwd: root, detached: true, stdio: ['ignore', output, output] }); + closeSync(output); + await new Promise((done, reject) => { child.once('spawn', done); child.once('error', reject); }); + const pid = child.pid!; + const identity = marker(pid); + if (!identity) throw new Error(`Watcher exited at startup. Read ${log}`); + writeFileSync(record, JSON.stringify({ pid, marker: identity })); + child.unref(); + // Bounded startup observation; a slow compile keeps running and status can + // inspect it later. Never mistake a live process for a completed publish. + for (let i = 0; i < 50; i++) { + if (marker(pid) !== identity) throw new Error(`Watcher exited. Read ${log}`); + if (existsSync(ready)) { console.log(`Running; initial publish and bindings completed. Log: ${log}`); return; } + await delay(100); + } + console.log(`Starting; initial publish not yet confirmed. Run spacetime-dev status. Log: ${log}`); +} + +if (process.argv[1] && resolve(process.argv[1]) === fileURLToPath(import.meta.url)) { + main(process.argv.slice(2)).catch(error => { console.error(error.message); process.exitCode = 1; }); +} diff --git a/tools/stack-bench/container/spacetimedb-binaries.json b/tools/stack-bench/container/spacetimedb-binaries.json new file mode 100644 index 00000000000..51e4e8a5fd4 --- /dev/null +++ b/tools/stack-bench/container/spacetimedb-binaries.json @@ -0,0 +1,21 @@ +{ + "schemaVersion": 2, + "platform": "linux/amd64", + "builderImage": "rust:1.93-slim-bookworm@sha256:8f8609d448e821fbc0e44241bc5ca4ce49663cc6306ff1a17f655a0e2a7cd084", + "source": { + "identityScheme": "git-object-content-v1", + "revision": "81ab0550c6e07cd24b264a9c32d9240ff4cf2d75", + "sha256": "bacff6fdae08ea390eabbfd1fe908b3cf1338a744272c0684d7857c77f630f64", + "files": 2599 + }, + "binaries": { + "spacetimedb-cli": { + "sha256": "2f671b85f51beac7ab6d32ccf707f08e3ca936d876fb2bdc874e02e497e5287f", + "size": 47642320 + }, + "spacetimedb-standalone": { + "sha256": "53df19d77e81ef61426e0bfd154d78e94b4e9a04754647d79777ff4e056163c9", + "size": 132331544 + } + } +} diff --git a/tools/stack-bench/dashboard/README.md b/tools/stack-bench/dashboard/README.md new file mode 100644 index 00000000000..ba9edaab5fb --- /dev/null +++ b/tools/stack-bench/dashboard/README.md @@ -0,0 +1,188 @@ +# Stack Bench dashboard + +The dashboard is an optional local view over Stack Bench results. It does not +schedule attempts, grade applications, or repair source itself. +Campaign plans, durable campaign state, and run artifacts remain the source of +truth. Appliance controls call the shared job and campaign operations. The +dashboard does not have a separate execution engine. + +## Pages + +- Campaigns (`/`) — a lane per running attempt, then one row per campaign with + its shape, status, and per-stack score. A campaign whose plan or state this + build cannot read appears with the status `unreadable` and the reason in + place of its title. +- Campaign (`/c/:key`) — plan facts, completion, scores, repairs, time, spend, + and attempts. The chart switches between completion, cost, and distribution + with `?chart=completion|cost|distribution`. Features are the default unit; + `&unit=features|checks` switches completion and distribution. Cost keeps these + controls visible but disabled. Toggle a stack or a repetition to show or hide it. + Dependency campaigns add questline rows, which + `?questlines=grid|graph|replay` switches between; `&step=N` moves the replay + cursor. Sequential campaigns show one row pair per level instead. +- Attempt (`/c/:key/a/:attemptId`) — attempt figures, the dependency graph, and + `?tab=checks|transcript|screenshots|files|log`. The transcript shows build and + repair sessions, including tool calls. It follows live work at the newest + page and pauses updates while you read earlier messages. The log tab shows + controller output separately. + In Checks, expand a requirement to see the recorded status, summary, expected + value and observation for each grade. Missing details remain explicit. These + are raw grading observations, including unsuccessful repairs; the accepted + score remains in the run summary. Blocked, inconclusive and harness failures + retain their recorded status. Credentials and marked sensitive details are omitted. +- New run (`/new`) — select workload, level, stacks, models, guidance, repetitions, + repairs, and limits. Review the attempt count and cost cap, then start. +- Saved plans (`/plans`) — inspect the exact configuration behind each run. + +## Modes + +"Before repairs" uses first-build evidence before repairs at each level. +Later levels retain earlier fixes and feedback; this is not a feedback-free run. + +Inside the appliance (`STACK_BENCH_APPLIANCE=1`) the dashboard runs in +controller mode: Start and Resume launch the CLI in an owned controller +container. Stop sends a durable request to that controller instance. +Stop interrupts the active attempt; it does not pause it. Resume starts +scheduled dependency work and does not restart a stopped sequential attempt. +It cannot restore a lost database or agent session. A planned depth pause uses +the CLI's `pause-status` and `continue-depth` commands and requires the original +controller to stay running. See [pause behavior](../README.md#pause-before-a-later-depth). +Elsewhere it runs read-only and those controls are unavailable; +`GET /api/health` reports which mode is active. + +From `tools/stack-bench`, `npm run dashboard` starts a read-only host view over +`tools/stack-bench/results`. Pass `--port` to move it off 7331 and `--results` +to point it at another results directory. + +## Appliance + +Run these commands from `tools/stack-bench` after the +[appliance setup](../appliance/README.md). + +```sh +docker compose --env-file operator.env \ + -f appliance/docker-compose.yaml --profile dashboard up -d dashboard +``` + +Open `http://127.0.0.1:7331`. Docker publishes that port only on the host's +loopback interface. Stop it with: + +```sh +docker compose --env-file operator.env \ + -f appliance/docker-compose.yaml --profile dashboard stop dashboard +``` + +Run controls need no separate password. This is a local, single-user dashboard: +the port binds to loopback, requests must use a loopback Host, and writes require +the exact browser origin and a per-server CSRF token. Other websites cannot read +that token. Local processes that can access the dashboard are trusted. Do not +publish this service through a proxy or on a shared network without authentication. +Model credentials remain private. Starting a run submits +an idempotent execution job and starts its worker in an +owned controller. Retrying Start with the same reviewed settings returns the same +job. A queued job has a status page before its campaign artifacts exist. + +The campaign page lists every attempt with its variant and repetition. Check +completion uses all selected checks, including checks not reached. Feature +completion requires all selected checks of a feature to pass, including its +production guarantees. Weighted score remains a separate measure. Spend includes +all executions and shows upper bounds and unknown values. Different comparison +conditions do not share one score average. Files links to the report and its +public export manifest; the manifest lists evidence and any reconstruction gaps. +Charts connect saved observations; intermediate values are not measured. +Comparison summaries and the distribution use eligible completed attempts. +Excluded attempts remain labelled in chart controls and the Runs table. Cost and +progress-over-time charts retain their observations, with the same exclusion label. +Live progress and total spend include unfinished work; total spend also includes +excluded attempts. These operational values are separate from comparison metrics. + +## Routes + +| route | returns | +| --- | --- | +| `GET /api/health` | `read-only` or `controller` | +| `GET /api/overview` | one summary per campaign | +| `GET /api/campaigns/:key` | the campaign sheet | +| `GET /api/campaigns/:key/live` | live spend, cost observations, activity, and phase | +| `GET /api/campaigns/:key/progression` | the dependency graph and its replay | +| `GET /api/campaigns/:key/attempts/:id/checks` | per-check outcome and history | +| `GET /api/campaigns/:key/attempts/:id/package` | the evidence listing | +| `GET /api/campaigns/:key/attempts/:id/log?from=N` | log bytes after `N` | +| `GET /api/campaigns/:key/attempts/:id/transcript` | selected session and paged transcript messages | +| `GET /api/campaigns/:key/attempts/:id/time` | time allowance, grants, and continuation eligibility | +| `POST /api/campaigns/:key/attempts/:id/time` | request additional time | +| `GET /api/campaigns/:key/artifacts/:name` | one allowlisted artifact | +| `GET /api/events` | the change stream | +| `GET /api/plans` | the discovered plans | +| `POST /api/campaigns` | start a run | +| `POST /api/campaigns/:key/resume` | run eligible scheduled dependency work | +| `POST /api/campaigns/:key/stop` | stop the exact controller shown by the page | + +The [job API](../docs/execution-jobs.md#api-and-service-integration) adds durable +submission, listing, status, and cancellation at `/api/jobs`. Submission queues +work; an enabled worker must claim it before execution starts. + +Each payload covers one question, so opening a campaign or a tab is what pays +for reading it. The overview and the sheet are cached against the size and +modification time of the evidence they read, including while a campaign runs. + +## The event stream + +`GET /api/events` is a server-sent event stream. A `campaign` event names a +campaign whose plan, state, run output, or progression state changed; a `log` +event names an attempt whose stdout grew. Changes are debounced for 500 ms and +the stream sends a comment every 25 seconds so an idle connection stays open. +Campaign events refresh the affected evidence. Log events fetch only live fields +and the open log or transcript. The client also refreshes live fields every five +seconds while runs are active; Claude Code and Codex usage can advance without a +controller log write. Live-cost reads share a server cache and concurrent reads. +Docker transcript reads time out after five seconds; a failed read keeps saved +receipts visible. Logs do not invalidate the evidence sheet or graph replay. +While the stream is down, a full refresh every 15 seconds recovers missed evidence +changes. Hidden tabs stop both the event stream and refresh work. + +The watcher uses a recursive `fs.watch` per campaign directory. Where the +platform or the mount does not support one it polls the same file fingerprints +every 5 seconds instead. The server logs which mode it opened with when the +first client subscribes. + +## What it touches + +It reads plans from `/plans`, campaigns from `/campaigns`, and +jobs from `/jobs`. Authorized controls use the shared APIs to write job, +cancellation, and time-grant records. The dashboard records direct controller +operations in `/dashboard/operations.jsonl` and retains their output +under `/dashboard/operations`. Live transcript reads inspect the exact +owned coding container; saved transcripts use the attempt's transcript files. +It does not edit grades or source. + +## Workload setup and AI access + +Appliance setup installs workload presets under `results/run-presets/`. Each preset +uses the existing campaign manifest format. It supplies the supported levels, +stacks, priced models, guidance conditions, and pinned runtime. Operators can add +approved models and conditions there. Setup does not replace existing presets; +update their runtime pins when deploying a new release. Invalid presets report their +errors. Model prices are recorded values; the dashboard does not guess prices. + +Both interfaces use `src/campaigns/run-setup.ts` and the existing execution jobs: + +```sh +node dist/commands/job-cli.js options --results /path/to/results +node dist/commands/job-cli.js prepare selections.json --results /path/to/results > review.json +node dist/commands/job-cli.js start review.json --results /path/to/results --host local +``` + +`options` returns each workload's choices and defaults. `prepare` takes `key`, +`workload`, `workloadSha256` (from options), `level`, `stacks`, `agents` (`index` and `effort`), `conditions`, +`repetitions`, `parallelism`, `repairs`, `timeoutMinutes`, `maxCostUsd`, +`pauseAfterDepth` (null for none), and `credentials` (empty for appliance defaults). +The response records the review identity, immutable plan, cost cap, account mode, +and grading qualification. `start` accepts that response. Any change requires a +new review. It starts the same worker as the dashboard and returns the job ID before +waiting for completion. No model or reasoning level is substituted. + +HTTP clients use `GET /api/run-setup`, `POST /api/runs/prepare`, and `POST /api/runs`. +Writes require the same origin and browser token as other controls. +Named credential profiles expose only their labels, provider, version, and account +mode. Secret paths and values remain on the server. diff --git a/tools/stack-bench/dashboard/dashboard-events.ts b/tools/stack-bench/dashboard/dashboard-events.ts new file mode 100644 index 00000000000..09bb3279b16 --- /dev/null +++ b/tools/stack-bench/dashboard/dashboard-events.ts @@ -0,0 +1,164 @@ +import { existsSync, readdirSync, statSync, watch } from 'node:fs'; +import type { FSWatcher } from 'node:fs'; +import { join } from 'node:path'; + +import { ARTIFACT_FILE } from '../src/evidence/artifacts.js'; +import { CAMPAIGN_FILE } from '../src/campaigns/campaign-path.js'; + +const DEBOUNCE_MS = 500; +const POLL_MS = 5000; +const LOG_FILE = 'process.stdout.log'; +const CAMPAIGN_FILES = [CAMPAIGN_FILE.plan, CAMPAIGN_FILE.state, 'depth-release.json'] as const; +const EXECUTION_FILES = [ARTIFACT_FILE.run, ARTIFACT_FILE.progressionState, 'depth-pause.json'] as const; + +export interface CampaignChange { + type: 'campaign' | 'log'; + key: string; + attemptId?: string; +} + +export type WatchMode = 'watch' | 'poll'; + +export interface CampaignWatcher { + close(): void; +} + +interface CampaignFingerprint { + campaign: string; + logs: Map; +} + +function stamp(path: string): string | null { + if (!existsSync(path)) return null; + const stat = statSync(path); + return `${stat.size}:${stat.mtimeMs}`; +} + +function directories(root: string): string[] { + if (!existsSync(root)) return []; + return readdirSync(root, { withFileTypes: true }) + .filter(entry => entry.isDirectory()).map(entry => entry.name); +} + +// The evidence a view reads, in one pass: the campaign files and each +// execution's result, and the log sizes that tell a follower there are new +// bytes to fetch. +function fingerprintCampaign(directory: string): CampaignFingerprint { + const parts = CAMPAIGN_FILES.map(file => `${file}:${stamp(join(directory, file)) ?? 'missing'}`); + const logs = new Map(); + const attemptsRoot = join(directory, 'attempts'); + for (const attempt of directories(attemptsRoot)) { + const attemptDirectory = join(attemptsRoot, attempt); + let bytes = 0; + for (const execution of directories(attemptDirectory)) { + const executionDirectory = join(attemptDirectory, execution); + for (const file of EXECUTION_FILES) { + const value = stamp(join(executionDirectory, file)); + if (value) parts.push(`${attempt}/${execution}/${file}:${value}`); + } + const log = join(executionDirectory, LOG_FILE); + if (existsSync(log)) bytes += statSync(log).size; + } + logs.set(attempt, bytes); + } + return { campaign: parts.sort().join('|'), logs }; +} + +// One watcher for the whole server: a recursive watch per campaign directory +// where the platform supports it (Windows, macOS, and Linux on Node 20 and +// later), and a poll of the same fingerprints where it does not. +export function watchCampaigns(campaignsRoot: string, + emit: (change: CampaignChange) => void, + onMode: (mode: WatchMode) => void = () => {}): CampaignWatcher { + const fingerprints = new Map(); + const watchers = new Map(); + const timers = new Map(); + let rootWatcher: FSWatcher | null = null; + let poll: NodeJS.Timeout | null = null; + let closed = false; + + const check = (key: string): void => { + timers.delete(key); + const directory = join(campaignsRoot, key); + if (!existsSync(directory)) { + fingerprints.delete(key); + watchers.get(key)?.close(); + watchers.delete(key); + return; + } + const next = fingerprintCampaign(directory); + const previous = fingerprints.get(key); + fingerprints.set(key, next); + if (!previous) return; + if (previous.campaign !== next.campaign) emit({ type: 'campaign', key }); + for (const [attemptId, bytes] of next.logs) { + if ((previous.logs.get(attemptId) ?? 0) !== bytes) emit({ type: 'log', key, attemptId }); + } + }; + + const schedule = (key: string): void => { + if (closed || timers.has(key)) return; + timers.set(key, setTimeout(() => check(key), DEBOUNCE_MS).unref()); + }; + + const startPoll = (): void => { + if (closed || poll) return; + onMode('poll'); + poll = setInterval(() => { + attach(); + for (const key of directories(campaignsRoot)) check(key); + }, POLL_MS).unref(); + }; + + const attach = (): void => { + if (closed) return; + if (!rootWatcher && existsSync(campaignsRoot)) { + try { + rootWatcher = watch(campaignsRoot, { persistent: false }, (_event, name) => { + const key = String(name ?? '').split(/[/\\]/)[0]; + if (key) schedule(key); + attach(); + }); + rootWatcher.once('error', () => { rootWatcher = null; startPoll(); }); + } catch { startPoll(); } + } + for (const key of directories(campaignsRoot)) { + // A campaign that appeared since the last pass has everything to report. + if (!fingerprints.has(key)) { + fingerprints.set(key, { campaign: '', logs: new Map() }); + schedule(key); + } + if (watchers.has(key) || poll) continue; + try { + const watcher = watch(join(campaignsRoot, key), { persistent: false, recursive: true }, + () => schedule(key)); + watcher.once('error', () => { watchers.delete(key); startPoll(); }); + watchers.set(key, watcher); + } catch { + // No recursive watch on this platform: the poll reads the same files. + startPoll(); + return; + } + } + }; + + for (const key of directories(campaignsRoot)) { + fingerprints.set(key, fingerprintCampaign(join(campaignsRoot, key))); + } + attach(); + if (!rootWatcher) startPoll(); + else if (!poll) onMode('watch'); + return { + close() { + closed = true; + for (const timer of timers.values()) clearTimeout(timer); + timers.clear(); + if (poll) clearInterval(poll); + poll = null; + rootWatcher?.close(); + rootWatcher = null; + for (const watcher of watchers.values()) watcher.close(); + watchers.clear(); + }, + }; +} diff --git a/tools/stack-bench/dashboard/dashboard-live-cost.ts b/tools/stack-bench/dashboard/dashboard-live-cost.ts new file mode 100644 index 00000000000..d38466bb0fe --- /dev/null +++ b/tools/stack-bench/dashboard/dashboard-live-cost.ts @@ -0,0 +1,119 @@ +import { attemptTranscriptFiles } from './dashboard-transcript.js'; +import { normalizeClaudeUsage, priceClaudeUsage } from '../src/evidence/claude-usage-cost.js'; +import type { PricingRates } from '../src/evidence/pricing-authority.js'; + +interface UsagePoint { id: string; completedAt: string; costUsd: number; signature: string } +export function liveCostTotal(status: string, observed: number | undefined, saved: number | null): number | undefined { + return status === 'running' && observed !== undefined && observed >= (saved ?? 0) ? observed : undefined; +} +const object = (value: unknown): value is Record => + !!value && typeof value === 'object' && !Array.isArray(value); + +// Display-only usage. Never write these observations into benchmark evidence. +export function responseCosts(text: string, rates: PricingRates, model: string, startedAt: string): UsagePoint[] { + const points: UsagePoint[] = []; + for (const line of text.split('\n')) { + if (!line.trim()) continue; + let event: unknown; + try { event = JSON.parse(line); } catch { throw new Error('Incomplete usage transcript'); } + if (!object(event) || event.type !== 'assistant' || !object(event.message) || !event.message.usage) continue; + const message = event.message; + if (typeof message.stop_reason !== 'string' || !message.stop_reason) continue; + const timestamp = typeof event.timestamp === 'string' ? Date.parse(event.timestamp) : NaN; + if (!Number.isFinite(timestamp)) throw new Error('Usage timestamp unavailable'); + if (timestamp < Date.parse(startedAt)) continue; + if (typeof message.model !== 'string' || !(message.model === model || message.model.startsWith(`${model}-`))) { + throw new Error('No pinned price for transcript model'); + } + const id = event.requestId ?? message.id ?? event.uuid; + if (typeof id !== 'string' || !id) throw new Error('Usage request identity unavailable'); + points.push({ id, completedAt: new Date(timestamp).toISOString(), + costUsd: priceClaudeUsage(message.usage, rates), + signature: JSON.stringify([message.model, normalizeClaudeUsage(message.usage)]) }); + } + return points; +} + +export function cumulativeResponseCosts(points: readonly UsagePoint[]): Array<{ completedAt: string; costUsd: number }> { + const unique = new Map(); + for (const point of points) { + const prior = unique.get(point.id); + if (prior && prior.signature !== point.signature) throw new Error('Conflicting usage for request'); + if (!prior) unique.set(point.id, point); + } + let total = 0; + return [...unique.values()].sort((a, b) => a.completedAt.localeCompare(b.completedAt)).map(point => ({ + completedAt: point.completedAt, costUsd: Number((total += point.costUsd).toFixed(6)), + })); +} + +interface CodexUsageState { session?: string; model?: string; totals?: [number, number, number] } + +export function codexResponseCosts(text: string, rates: PricingRates, model: string, startedAt: string): UsagePoint[] { + const state: CodexUsageState = {}; + const points: UsagePoint[] = []; + for (const line of text.split('\n')) { + if (!line.trim()) continue; + const event: unknown = JSON.parse(line); + if (!object(event) || !object(event.payload)) continue; + const payload = event.payload; + if (event.type === 'session_meta') { + if (typeof payload.id !== 'string' || !payload.id) throw new Error('Usage session identity unavailable'); + if (state.session && state.session !== payload.id) throw new Error('Usage session changed'); + state.session = payload.id; + } + if (event.type === 'turn_context') state.model = typeof payload.model === 'string' ? payload.model : undefined; + if (event.type !== 'event_msg' || payload.type !== 'token_count' || payload.info === null) continue; + const usage = object(payload.info) && object(payload.info.total_token_usage) + ? payload.info.total_token_usage : {}; + const totals = [usage.input_tokens, usage.cached_input_tokens, usage.output_tokens]; + if (!totals.every(value => typeof value === 'number' && Number.isSafeInteger(value) && value >= 0) + || Number(totals[1]) > Number(totals[0])) throw new Error('Invalid Codex token usage'); + const counts = totals as [number, number, number]; + const previous = state.totals ?? [0, 0, 0]; + const delta = [counts[0] - previous[0], counts[1] - previous[1], counts[2] - previous[2]] as const; + if (delta.some(value => value < 0) || delta[1] > delta[0]) throw new Error('Codex usage totals decreased'); + state.totals = counts; + const timestamp = typeof event.timestamp === 'string' ? Date.parse(event.timestamp) : NaN; + if (!Number.isFinite(timestamp)) throw new Error('Usage timestamp unavailable'); + if (timestamp < Date.parse(startedAt) || delta.every(value => value === 0)) continue; + if (!state.session) throw new Error('Usage session identity unavailable'); + if (state.model !== model) throw new Error('No pinned price for transcript model'); + points.push({ id: `${state.session}:${counts.join(':')}`, completedAt: new Date(timestamp).toISOString(), + costUsd: ((delta[0] - delta[1]) * rates.input + delta[1] * rates.cacheRead + delta[2] * rates.output) / 1e6, + signature: JSON.stringify([state.model, delta]) }); + } + return points; +} + +const cache = new Map(); + +export async function liveTranscriptCost(directory: string, adapter: string, rates: PricingRates, + model: string, startedAt: string) { + const files = await attemptTranscriptFiles([{ directory, label: 'Execution' }], adapter); + const activityUpdatedAt = files.length ? new Date(Math.max(...files.map(file => file.modified))).toISOString() : null; + const points: UsagePoint[] = []; + for (const file of files) { + const key = `${directory}/${file.id}/${startedAt}/${JSON.stringify(rates)}/${model}`; + const prior = cache.get(key); + if (prior?.size === file.size && prior.modified === file.modified) { points.push(...prior.points); continue; } + // Read Codex session metadata and cumulative counters together. + const offsetStart = adapter !== 'codex' && prior && file.size > prior.size ? prior.offset : 0; + // Bound catch-up work; do not label a partial file as a complete live total. + if (file.size - offsetStart > 16 * 1024 * 1024) return { activityUpdatedAt, costs: [] }; + const chunks: Buffer[] = []; + for (let offset = offsetStart; offset < file.size; offset += 256 * 1024) { + chunks.push(await file.read(offset, Math.min(256 * 1024, file.size - offset))); + } + const bytes = Buffer.concat(chunks); + const end = bytes.lastIndexOf(10); + const text = end < 0 ? '' : bytes.subarray(0, end + 1).toString(); + const parsed = [...(offsetStart ? prior!.points : []), ...(adapter === 'codex' + ? codexResponseCosts(text, rates, model, startedAt) + : responseCosts(text, rates, model, startedAt))]; + if (cache.size >= 128) cache.delete(cache.keys().next().value!); + cache.set(key, { size: file.size, modified: file.modified, offset: offsetStart + end + 1, points: parsed }); + points.push(...parsed); + } + return { activityUpdatedAt, costs: cumulativeResponseCosts(points) }; +} diff --git a/tools/stack-bench/dashboard/dashboard-model.ts b/tools/stack-bench/dashboard/dashboard-model.ts new file mode 100644 index 00000000000..908a9429aa3 --- /dev/null +++ b/tools/stack-bench/dashboard/dashboard-model.ts @@ -0,0 +1,521 @@ +import { closeSync, existsSync, fstatSync, openSync, readFileSync, readSync, readdirSync, + lstatSync, realpathSync, statSync, +} from 'node:fs'; +import { basename, dirname, extname, join, relative, resolve, sep } from 'node:path'; + +import type { CompiledCampaignPlan } + from '../src/campaigns/campaign-compiler.js'; +import type { CampaignAttemptState } from '../src/campaigns/campaign-scheduler.js'; +import { ARTIFACT_FILE } from '../src/evidence/artifacts.js'; +import { compileCampaignFile } from '../src/campaigns/campaign-compiler.js'; +import { campaignLockIsActive, readCampaignLock } from '../src/campaigns/campaign-lock.js'; +import { readDepthPause } from '../src/campaigns/campaign-depth-pause.js'; +import { readCampaignState } from '../src/campaigns/campaign-scheduler.js'; +import { campaignFacts, inspectCampaignAttempt } from '../src/campaigns/campaign-inspection.js'; +import { redactCredentials } from '../src/evidence/diagnostic-sanitizer.js'; +import { CAMPAIGN_FILE } from '../src/campaigns/campaign-path.js'; +import { repairBudgetLimit } from '../src/progression/repair-plan.js'; + +export const MAX_LOG_BYTES = 96 * 1024; +const MAX_PUBLIC_TEXT_BYTES = 8 * 1024 * 1024; +const MAX_ARTIFACTS_PER_EXECUTION = 512; +const IMAGE_TYPES = new Map([ + ['.png', 'image/png'], ['.jpg', 'image/jpeg'], ['.jpeg', 'image/jpeg'], ['.webp', 'image/webp'], +]); +const CAMPAIGN_ARTIFACT = /^(?:plan\.json|state\.json|report\/(?:report\.(?:html|json)|export-manifest\.json))$/; +const EXECUTION_ARTIFACT = /^(?:run\.json|preflight\.json|recovery\.json|progression-state\.json|process\.json|process\.(?:stdout|stderr)\.log|backend\.log|level-l\d+-checkpoint\.json|progression\/attempt-\d+\/(?:bundle\.json|contract-lint\.json|actions\.json|grading-[^/]+\.json|failure-media\/[^/]+\.(?:png|jpe?g|webp))|(?:first-build-l\d+-grading|l\d+-fix\d+-grading|grading)\/(?:bundle\.json|contract-lint\.json|actions\.json|grading-[^/]+\.json|failure-media\/[^/]+\.(?:png|jpe?g|webp)))$/i; + +type ControllerActive = (directory: string, campaign: CompiledCampaignPlan) => boolean; + +export interface DashboardArtifact { + id: string; + path: string; + name: string; + kind: 'visual' | 'report' | 'log' | 'data'; + contentType: string; + size: number; +} + +export interface ResolvedDashboardArtifact extends DashboardArtifact { + absolute: string; +} + +function errorMessage(error: unknown): string { + return error instanceof Error ? error.message : String(error); +} + +export function contained(root: string, path: string, label: string): string { + const absoluteRoot = resolve(root); + const absolute = resolve(absoluteRoot, path); + const rel = relative(absoluteRoot, absolute); + if (rel === '..' || rel.startsWith(`..${sep}`) || rel === '') { + throw new Error(`${label} is outside the configured dashboard root`); + } + return absolute; +} + +export function readTextTail(path: string, limit = MAX_LOG_BYTES): string { + if (!existsSync(path)) return ''; + const descriptor = openSync(path, 'r'); + try { + const size = fstatSync(descriptor).size; + const length = Math.min(size, limit); + const buffer = Buffer.alloc(length); + readSync(descriptor, buffer, 0, length, size - length); + return redactCredentials(buffer.toString('utf8')); + } finally { + closeSync(descriptor); + } +} + +function artifactId(relativePath: string): string { + return Buffer.from(relativePath, 'utf8').toString('base64url'); +} + +function artifactLabel(path: string): string { + const name = basename(path); + if (path === CAMPAIGN_FILE.plan) return 'Frozen plan'; + if (path === CAMPAIGN_FILE.state) return 'Campaign state'; + if (path === `report/${CAMPAIGN_FILE.reportHtml}`) return 'Campaign report'; + if (path === `report/${CAMPAIGN_FILE.reportJson}`) return 'Report data'; + if (name === ARTIFACT_FILE.run) return 'Run result'; + if (name === ARTIFACT_FILE.preflight) return 'Preflight result'; + if (name === ARTIFACT_FILE.recovery) return 'Recovery record'; + if (name === ARTIFACT_FILE.progressionState) return 'Dependency progress'; + if (name === 'process.stdout.log') return 'Run output'; + if (name === 'process.stderr.log') return 'Run errors'; + if (name === 'backend.log') return 'Backend output'; + if (name === ARTIFACT_FILE.gradeBundle) return `${basename(dirname(path))} bundle`; + if (name === ARTIFACT_FILE.actions) return `${basename(dirname(path))} actions`; + if (name === ARTIFACT_FILE.contractLint) return `${basename(dirname(path))} contract check`; + return name.replace(/[-_]/g, ' '); +} + +function artifactMetadata(campaignDirectory: string, path: string): DashboardArtifact { + const absolute = contained(campaignDirectory, path, 'campaign artifact'); + const size = statSync(absolute).size; + const extension = extname(path).toLowerCase(); + const kind = IMAGE_TYPES.has(extension) ? 'visual' + : path.endsWith('/report.html') ? 'report' + : path.endsWith('.log') ? 'log' : 'data'; + return { id: artifactId(path), path: path.replaceAll('\\', '/'), name: artifactLabel(path), + kind, contentType: IMAGE_TYPES.get(extension) ?? (kind === 'report' ? 'text/html' : 'text/plain'), + size }; +} + +function rejectSymlinkPath(root: string, path: string): void { + const rel = relative(resolve(root), resolve(path)); + let current = resolve(root); + for (const segment of rel.split(sep)) { + current = join(current, segment); + if (lstatSync(current).isSymbolicLink()) { + throw new Error('campaign artifact path contains a symbolic link'); + } + } +} + +export function walkPublicExecutionArtifacts(campaignDirectory: string, executionDirectory: string): { + artifacts: DashboardArtifact[]; + truncated: boolean; +} { + const found: DashboardArtifact[] = []; + let truncated = false; + const visit = (directory: string): void => { + const directoryRelative = relative(executionDirectory, directory).replaceAll('\\', '/'); + for (const entry of readdirSync(directory, { withFileTypes: true })) { + if (found.length >= MAX_ARTIFACTS_PER_EXECUTION) { + truncated = true; + return; + } + if (entry.isSymbolicLink()) continue; + const absolute = join(directory, entry.name); + if (entry.isDirectory()) { + const allowed = directoryRelative === '' + ? /^(?:first-build-l\d+-grading|l\d+-fix\d+-grading|grading|progression)$/i.test(entry.name) + : directoryRelative === 'progression' + ? /^attempt-\d+$/i.test(entry.name) + : (/^(?:progression\/attempt-\d+|(?:.*\/)?(?:first-build-l\d+-grading|l\d+-fix\d+-grading|grading))$/i + .test(directoryRelative) && entry.name === 'failure-media'); + if (allowed) visit(absolute); + if (truncated) return; + } + else if (entry.isFile()) { + const executionRelative = relative(executionDirectory, absolute).replaceAll('\\', '/'); + if (EXECUTION_ARTIFACT.test(executionRelative)) { + const campaignRelative = relative(campaignDirectory, absolute).replaceAll('\\', '/'); + found.push(artifactMetadata(campaignDirectory, campaignRelative)); + } + } + } + }; + if (existsSync(executionDirectory)) visit(executionDirectory); + return { artifacts: found.sort((left, right) => left.path.localeCompare(right.path)), truncated }; +} + +function campaignPackage(campaignDirectory: string, attempts: CampaignAttemptState[]) { + const campaign = [CAMPAIGN_FILE.plan, CAMPAIGN_FILE.state, + `report/${CAMPAIGN_FILE.reportHtml}`, `report/${CAMPAIGN_FILE.reportJson}`] + .filter(path => existsSync(join(campaignDirectory, path))) + .map(path => artifactMetadata(campaignDirectory, path)); + const executions: Array<{ + attemptId: string; + stack: string; + executionId: string; + ordinal: number; + status: string; + artifacts: DashboardArtifact[]; + visuals: DashboardArtifact[]; + truncated: boolean; + }> = []; + for (const attempt of attempts) { + for (const execution of attempt.executions) { + const directory = contained(campaignDirectory, execution.output, 'campaign execution'); + const scanned = walkPublicExecutionArtifacts(campaignDirectory, directory); + const artifacts = scanned.artifacts; + executions.push({ attemptId: attempt.plan.id, stack: attempt.plan.stack, + executionId: execution.id, ordinal: execution.ordinal, status: execution.status, + artifacts, visuals: artifacts.filter(artifact => artifact.kind === 'visual'), + truncated: scanned.truncated }); + } + } + return { campaign, executions }; +} + +export function resolveCampaignArtifact(resultsRoot: string, key: string, + id: string): ResolvedDashboardArtifact { + if (!/^[a-z0-9][a-z0-9.-]*$/.test(key)) throw new Error('campaign key is invalid'); + let path; + try { path = Buffer.from(id, 'base64url').toString('utf8'); } + catch { throw new Error('campaign artifact id is invalid'); } + if (!path || artifactId(path) !== id || path.includes('\\') || path.startsWith('/')) { + throw new Error('campaign artifact id is invalid'); + } + const executionMatch = path.match(/^attempts\/([^/]+)\/(execution-\d+)\/(.+)$/); + const allowed = CAMPAIGN_ARTIFACT.test(path) + || (executionMatch !== null && EXECUTION_ARTIFACT.test(executionMatch[3] ?? '')); + if (!allowed) { + throw new Error('campaign artifact is not available in the dashboard'); + } + const campaignsRoot = join(resolve(resultsRoot), 'campaigns'); + const campaignDirectory = contained(campaignsRoot, key, 'campaign'); + const absolute = contained(campaignDirectory, path, 'campaign artifact'); + if (!existsSync(absolute) || !statSync(absolute).isFile()) throw new Error('campaign artifact does not exist'); + rejectSymlinkPath(campaignsRoot, absolute); + const realCampaign = realpathSync(campaignDirectory); + const realArtifact = realpathSync(absolute); + contained(realCampaign, relative(realCampaign, realArtifact), 'campaign artifact'); + return { ...artifactMetadata(campaignDirectory, path), absolute }; +} + +export function readCampaignArtifactBody(artifact: ResolvedDashboardArtifact): Buffer { + if (artifact.kind === 'visual') return readFileSync(artifact.absolute); + if (artifact.size > MAX_PUBLIC_TEXT_BYTES) throw new Error('campaign artifact is too large to view'); + return Buffer.from(redactCredentials(readFileSync(artifact.absolute, 'utf8'))); +} + +function matches(text: string, pattern: RegExp): Array { + return [...text.matchAll(pattern)].map(match => Object.assign(match, { index: match.index ?? 0 })); +} + +export function parseRunProgress(log: string, { repairs = 0, running = true, status = null, + dependency = false }: { + repairs?: number; + running?: boolean; + status?: string | null; + dependency?: boolean; +} = {}) { + const totals = matches(log, /^\s*TOTAL\b.*?(\d+)\/(\d+)\s*$/gm) + .map(match => ({ index: match.index, score: Number(match[1]), max: Number(match[2]) })); + // A run-wide repair prints "repair N/M"; a feature repair prints + // "feature repair N: title" because its limit belongs to the feature. + const roundMarkers = matches(log, + /^--- (?:feature )?repair (\d+)(?:\/(\d+))?(?:: (.+))? ---$/gm) + .map(match => ({ index: match.index, round: Number(match[1]), + budget: match[2] === undefined ? null : Number(match[2]), + target: match[3] ?? null })); + const grading = matches(log, /^===\s+[^\n]*?-l(\d+)(?:-(?:first|fix(\d+)))?\s+\([^\n]+\)\s*===$/gm) + .map(match => ({ index: match.index, level: Number(match[1]), + round: match[2] ? Number(match[2]) : 0 })); + const latestTotal = totals.at(-1) ?? null; + const latestRound = roundMarkers.at(-1) ?? null; + const latestGrading = grading.at(-1) ?? null; + const latestIndex = Math.max(latestTotal?.index ?? -1, latestRound?.index ?? -1, + latestGrading?.index ?? -1); + let phase = status === 'pending' ? 'Waiting to start' + : running ? 'Building the generated app' + : status === 'invalid' ? 'Stopped without a valid result' : 'Finished'; + const level = latestGrading?.level ?? null; + const round = latestRound?.round ?? latestGrading?.round ?? 0; + const budget = latestRound ? latestRound.budget : repairs; + const target = latestRound?.target ? ` for ${latestRound.target}` : ''; + const of = (limit: number | null): string => limit === null ? '' : ` of ${limit}`; + const stage = (value: number): string => dependency ? `depth ${value}` : `L${value}`; + if (running && latestIndex === latestGrading?.index) { + phase = latestGrading.round + ? `Grading ${stage(latestGrading.level)} after repair ${round}${of(budget)}${target}` + : `Grading the first ${stage(latestGrading.level)} build`; + } else if (running && latestIndex === latestRound?.index) { + phase = latestRound.target + ? `Repairing ${latestRound.target} · ${latestRound.round}${of(latestRound.budget)}` + : `Repairing ${stage(latestGrading?.level ?? 1)} · round ${latestRound.round}${of(latestRound.budget)}`; + } else if (latestIndex === latestTotal?.index && running) { + phase = 'Preparing the next step'; + } + return { + phase, + level, + repair: { round, budget }, + firstScore: totals[0] ? { score: totals[0].score, max: totals[0].max } : null, + latestScore: latestTotal ? { score: latestTotal.score, max: latestTotal.max } : null, + completedGrades: totals.length, + // Every completed grade in order — the attempt's trajectory — carrying the + // level it graded and whether it was the unaided build of that level. A + // view can draw the climb with its bands, and a flat tail is the stall an + // operator otherwise discovers by diffing round logs. + series: totals.map(total => { + const mark = grading.findLast(entry => entry.index < total.index) ?? null; + return { score: total.score, max: total.max, level: mark?.level ?? null, + unaided: mark ? mark.round === 0 : false }; + }), + }; +} + +export function attemptPause(plan: CompiledCampaignPlan, attempt: CampaignAttemptState, + directory: string) { + const depth = plan.definition.mode.pauseAfterDepth; + const execution = attempt.executions.at(-1); + const lock = depth === undefined ? null : readCampaignLock(directory); + if (depth === undefined || !execution || !lock) return null; + return readDepthPause(contained(directory, execution.output, 'campaign execution'), { + directory, depth, campaignSha256: plan.contentSha256, + ownershipMarkerSha256: lock.ownershipMarkerSha256, + attemptId: attempt.plan.id, executionId: execution.id, + }); +} + +function summarizeAttempt(plan: CompiledCampaignPlan, attempt: CampaignAttemptState, + campaignDirectory: string, repairs: number, { includeLog = false }: { + includeLog?: boolean; + } = {}) { + const inspected = inspectCampaignAttempt(plan, attempt, campaignDirectory); + const execution = inspected.execution; + let executionDirectory = null; + let log = ''; + let logUpdatedAt = null; + if (execution) { + executionDirectory = contained(campaignDirectory, execution.output, 'campaign execution'); + const logPath = join(executionDirectory, 'process.stdout.log'); + log = readTextTail(logPath); + // When the run last wrote anything. A running attempt whose output has + // been silent for a long time is wedged in a way no score can show. + if (existsSync(logPath)) logUpdatedAt = new Date(statSync(logPath).mtimeMs).toISOString(); + } + const progress = parseRunProgress(log, { repairs, running: attempt.status === 'running', + status: attempt.status, dependency: plan.definition.mode.id === 'dependency' }); + const pause = attemptPause(plan, attempt, campaignDirectory); + const paused = attempt.status === 'running' && pause?.resumedAt === null; + if (paused) progress.phase = `Paused at L${pause.depth}`; + if (inspected.result?.score) progress.latestScore = inspected.result.score; + return { + ...inspected, + progress, + paused, + logUpdatedAt, + ...(includeLog ? { log: log.split(/\r?\n/).slice(-160).join('\n') } : {}), + }; +} + +export function summarizeCampaign(directory: string, { + includeLogs = false, + includePackage = false, + includeAttempts = true, + controllerActive = null, +}: { + includeLogs?: boolean; + includePackage?: boolean; + includeAttempts?: boolean; + controllerActive?: ControllerActive | null; +} = {}) { + const { plan, state } = readCampaignState(directory, { requireCurrentInputs: false }); + let attempts = includeAttempts + ? state.attempts.map(attempt => summarizeAttempt(plan, attempt, directory, + repairBudgetLimit(plan.definition.repair, { + features: plan.featureCatalog?.definition.nodes.length ?? 1, + depths: plan.definition.levels.length, + }), { includeLog: includeLogs })) + : []; + const interrupted = state.status === 'running' && controllerActive !== null + && !controllerActive(directory, plan); + if (interrupted) { + attempts = attempts.map(attempt => attempt.status !== 'running' ? attempt : ({ + ...attempt, + status: 'interrupted', + execution: attempt.execution ? { ...attempt.execution, status: 'interrupted' } : null, + progress: { ...attempt.progress, phase: 'Controller stopped before completion' }, + })); + } + return { + key: basename(resolve(directory)), + id: plan.id, + version: plan.version, + sha256: plan.contentSha256, + title: plan.title, + state: plan.state, + mode: plan.definition.mode?.id ?? 'sequential', + status: interrupted ? 'attention-required' : state.status, + track: plan.definition.track, + levels: plan.definition.levels, + stacks: plan.stacks.map(stack => stack.id), + repetitions: plan.definition.repetitions, + maxParallel: state.maxParallel, + createdAt: state.createdAt, + updatedAt: state.updatedAt, + summary: interrupted ? { ...state.summary, interrupted: state.summary.running, running: 0 } + : state.summary, + interrupted, + ...(interrupted ? { statusReason: 'The campaign controller is no longer running.' } : {}), + budgets: plan.definition.budgets, + facts: campaignFacts(plan), + attempts, + ...(includePackage ? { package: campaignPackage(directory, state.attempts) } : {}), + }; +} + +export interface UnreadableDashboardCampaign { + key: string; + id: string; + title: string; + status: 'unreadable'; + error: string; + attempts: []; +} + +export type DashboardCampaign = ReturnType; +export type DashboardCampaignSummary = DashboardCampaign | UnreadableDashboardCampaign; + +const overviewCampaignCache = new Map(); + +function summarizeOverviewCampaign(directory: string, includeAttempts: boolean, + controllerActive: ControllerActive): DashboardCampaign { + const fingerprint = [CAMPAIGN_FILE.plan, CAMPAIGN_FILE.state] + .map(file => { + const stat = statSync(join(directory, file)); + return `${stat.size}:${stat.mtimeMs}`; + }).join('|'); + const key = `${includeAttempts ? 'attempts' : 'summary'}:${directory}`; + const cached = overviewCampaignCache.get(key); + if (cached?.fingerprint === fingerprint) return cached.campaign; + const campaign = summarizeCampaign(directory, { includeAttempts, controllerActive }); + if (campaign.summary.running === 0) { + overviewCampaignCache.set(key, { fingerprint, campaign }); + } + return campaign; +} + +export function discoverCampaigns(campaignsRoot: string, { + includeLogs = false, + controllerActive = campaignLockIsActive, +}: { includeLogs?: boolean; controllerActive?: ControllerActive } = {}) { + if (!existsSync(campaignsRoot)) return []; + const campaigns: DashboardCampaignSummary[] = []; + for (const entry of readdirSync(campaignsRoot, { withFileTypes: true })) { + if (!entry.isDirectory()) continue; + const directory = join(campaignsRoot, entry.name); + if (!existsSync(join(directory, CAMPAIGN_FILE.state)) + || !existsSync(join(directory, CAMPAIGN_FILE.plan))) continue; + try { + campaigns.push(includeLogs + ? summarizeCampaign(directory, { includeLogs, controllerActive }) + : summarizeOverviewCampaign(directory, false, controllerActive)); + } catch (error) { + campaigns.push({ key: entry.name, id: entry.name, title: entry.name, + status: 'unreadable', error: errorMessage(error), attempts: [] }); + } + } + campaigns.sort((left, right) => String('updatedAt' in right ? right.updatedAt ?? '' : '') + .localeCompare(String('updatedAt' in left ? left.updatedAt ?? '' : ''))); + if (includeLogs) return campaigns; + + const verdict = campaigns.find(campaign => campaign.status === 'completed' + && 'facts' in campaign && campaign.facts.grading.status === 'qualified'); + return campaigns.map(campaign => { + if (campaign.status !== 'running' && campaign !== verdict) return campaign; + try { + return summarizeOverviewCampaign(join(campaignsRoot, campaign.key), true, controllerActive); + } catch (error) { + const unreadable: UnreadableDashboardCampaign = { + key: campaign.key, + id: campaign.id, + title: campaign.title, + status: 'unreadable', + error: errorMessage(error), + attempts: [], + }; + return unreadable; + } + }); +} + +export interface DashboardPlan { + id: string; + version?: string; + title: string; + state: string; + mode?: string; + track?: string; + levels?: number[]; + stacks?: string[]; + attempts?: number; + parallelism?: number; + budgets?: CompiledCampaignPlan['definition']['budgets']; + repairBudget?: number; + sha256?: string; + file: string; + error?: string; +} + +export function discoverPlans(plansRoot: string): DashboardPlan[] { + if (!existsSync(plansRoot)) return []; + const plans: DashboardPlan[] = []; + for (const entry of readdirSync(plansRoot, { withFileTypes: true })) { + if (!entry.isFile() || !entry.name.endsWith('.json')) continue; + const path = join(plansRoot, entry.name); + try { + const plan = compileCampaignFile(path); + plans.push({ id: plan.id, version: plan.version, title: plan.title, state: plan.state, + mode: plan.definition.mode?.id ?? 'sequential', + track: plan.definition.track, levels: plan.definition.levels, + stacks: plan.stacks.map(stack => stack.id), attempts: plan.summary.attempts, + parallelism: plan.summary.parallelism, budgets: plan.definition.budgets, + repairBudget: repairBudgetLimit(plan.definition.repair, { + features: plan.featureCatalog?.definition.nodes.length ?? 1, + depths: plan.definition.levels.length, + }), + sha256: plan.contentSha256, file: entry.name }); + } catch (error) { + plans.push({ id: entry.name.slice(0, -5), title: entry.name, state: 'invalid', + error: errorMessage(error), file: entry.name }); + } + } + return plans.sort((left, right) => left.title.localeCompare(right.title)); +} + +export function readJsonLines(path: string): unknown[] { + if (!existsSync(path)) return []; + const lines = readFileSync(path, 'utf8').split(/\r?\n/); + const last = lines.findLastIndex(line => line.trim() !== ''); + const events: unknown[] = []; + for (let index = 0; index <= last; index += 1) { + const line = lines[index]; + if (!line?.trim()) continue; + try { events.push(JSON.parse(line)); } + catch { + if (index === last) break; + throw new Error(`dashboard operation feed line ${index + 1} is invalid JSON`); + } + } + return events; +} diff --git a/tools/stack-bench/dashboard/dashboard-server.ts b/tools/stack-bench/dashboard/dashboard-server.ts new file mode 100644 index 00000000000..396933ff079 --- /dev/null +++ b/tools/stack-bench/dashboard/dashboard-server.ts @@ -0,0 +1,613 @@ +#!/usr/bin/env node +import { prepareRun, runSetupCatalog, submitPreparedRun } from '../src/campaigns/run-setup.js'; + +import { randomBytes, randomUUID, timingSafeEqual } from 'node:crypto'; +import { appendFileSync, closeSync, createReadStream, existsSync, mkdirSync, openSync, statSync } from 'node:fs'; +import { createServer } from 'node:http'; +import type { IncomingMessage, ServerResponse } from 'node:http'; +import { basename, dirname, join, resolve } from 'node:path'; +import { fileURLToPath, pathToFileURL } from 'node:url'; +import { spawn } from 'node:child_process'; +import { parseArgs as parseNodeArgs } from 'node:util'; + +import { contained, discoverPlans, readCampaignArtifactBody, + readJsonLines, resolveCampaignArtifact, summarizeCampaign, +} from './dashboard-model.js'; +import type { DashboardPlan } from './dashboard-model.js'; +import { attemptTranscript, attemptChecks, attemptLogSlice, attemptPackage, campaignLiveProgression, campaignLiveSheet, campaignLiveUpdate, + overviewSummary } from './dashboard-views.js'; +import { watchCampaigns } from './dashboard-events.js'; +import type { CampaignChange, CampaignWatcher } from './dashboard-events.js'; +import { STACK_BENCH_ROOT } from '../src/package-root.js'; +import { stackBenchResultsRoot } from '../src/runtime/operational-paths.js'; +import { controllerRuntimeCommand, controllerChildEnvironment } from '../appliance/controller.js'; +import { requestCampaignCancellation } from '../src/campaigns/campaign-lock.js'; +import { readCampaignTimeBudget, requestCampaignTimeGrant } from '../src/campaigns/campaign-time-grant.js'; +import { redactCredentials } from '../src/evidence/diagnostic-sanitizer.js'; +import { submitExecutionJob, listExecutionJobs, readExecutionJob, cancelExecutionJob } + from '../src/campaigns/execution-jobs.js'; + +const DASHBOARD_ROOT = dirname(fileURLToPath(import.meta.url)); +const PUBLIC_ROOT = join(DASHBOARD_ROOT, 'public'); +const SAFE_NAME = /^[a-z0-9][a-z0-9.-]{2,119}$/; +const SPA_PATH = /^\/(?:new|plans|c\/[^/]+(?:\/a\/[^/]+)?)$/; +const HEARTBEAT_MS = 25_000; +const LOOPBACK = new Set(['127.0.0.1', '::1', 'localhost']); +const STATIC = new Map([ + ['/', ['index.html', 'text/html; charset=utf-8']], + ['/app.js', ['app.js', 'text/javascript; charset=utf-8']], + ['/climb.js', ['climb.js', 'text/javascript; charset=utf-8']], + ['/format.js', ['format.js', 'text/javascript; charset=utf-8']], + ['/progress-chart.js', ['progress-chart.js', 'text/javascript; charset=utf-8']], + ['/graph.js', ['graph.js', 'text/javascript; charset=utf-8']], + ['/metrics.js', ['metrics.js', 'text/javascript; charset=utf-8']], + // Shared with the CLI so a state has one name on every surface. + ['/src/evidence/status-words.js', ['../../src/evidence/status-words.js', 'text/javascript; charset=utf-8']], + ['/views/attempt.js', ['views/attempt.js', 'text/javascript; charset=utf-8']], + ['/views/campaign.js', ['views/campaign.js', 'text/javascript; charset=utf-8']], + ['/views/campaigns.js', ['views/campaigns.js', 'text/javascript; charset=utf-8']], + ['/views/plans.js', ['views/plans.js', 'text/javascript; charset=utf-8']], + ['/views/run-setup.js', ['views/run-setup.js', 'text/javascript; charset=utf-8']], + ['/styles.css', ['styles.css', 'text/css; charset=utf-8']], + ['/spacetimedb-mark.svg', ['spacetimedb-mark.svg', 'image/svg+xml']], + // The brand faces are served from here rather than a CDN: the dashboard's own + // content-security-policy allows 'self' only, and the appliance has no + // outbound access to fetch them at view time. + ['/fonts/inter-latin-variable.woff2', ['fonts/inter-latin-variable.woff2', 'font/woff2']], + ['/fonts/source-code-pro-latin-variable.woff2', ['fonts/source-code-pro-latin-variable.woff2', 'font/woff2']], +]); + +interface DashboardArgs { + host: string; + port: number; + resultsRoot: string; + plansRoot: string; + allowContainerBind: boolean; +} + +export interface DashboardOperation { + id: string; + updatedAt: string; + [key: string]: unknown; +} + +function dashboardOperation(value: unknown): DashboardOperation { + if (!value || typeof value !== 'object') throw new Error('dashboard operation must be an object'); + const id = 'id' in value ? value.id : undefined; + const updatedAt = 'updatedAt' in value ? value.updatedAt : undefined; + if (typeof id !== 'string' || !id) throw new Error('dashboard operation id is required'); + if (typeof updatedAt !== 'string' || !updatedAt) { + throw new Error('dashboard operation updatedAt is required'); + } + return { ...value, id, updatedAt }; +} + +export interface OperationFeed { + readonly path?: string; + append(event: DashboardOperation): void; + list(): DashboardOperation[]; +} + +export interface LaunchChild { + pid?: number; + once(event: 'error', listener: (error: Error) => void): unknown; + once(event: 'exit', listener: (code: number | null, signal: NodeJS.Signals | null) => void): unknown; +} + +export interface LaunchInput { + command: 'resume' | 'work'; + jobId?: string; + plan: DashboardPlan & { path: string }; + output: string; + operationId: string; + resultsRoot: string; + feed: OperationFeed; + env?: NodeJS.ProcessEnv; +} + +export interface DashboardServerOptions { + resultsRoot: string; + plansRoot: string; + allowLaunch?: boolean; + token?: string; + feed?: OperationFeed; + launch?: (input: LaunchInput) => LaunchChild; + plans?: () => DashboardPlan[]; +} + +function errorMessage(error: unknown): string { + return redactCredentials(error instanceof Error ? error.message : String(error)); +} + +function loopbackHost(value: unknown): boolean { + return /^(?:localhost|127\.0\.0\.1|\[::1\])(?::\d+)?$/i.test(String(value ?? '')); +} + +function sameSecret(actual: unknown, expected: unknown): boolean { + if (typeof actual !== 'string' || typeof expected !== 'string') return false; + const left = Buffer.from(actual); + const right = Buffer.from(expected); + return left.length === right.length && timingSafeEqual(left, right); +} + +function controlAuthorized(request: IncomingMessage, host: string | undefined, + csrfToken: string): boolean { + return request.headers.origin === `http://${host}` + && sameSecret(request.headers['x-stack-bench-token'], csrfToken); +} + +export function parseDashboardArgs(argv: string[], env: NodeJS.ProcessEnv = process.env): DashboardArgs { + const { values } = parseNodeArgs({ args: argv.slice(2), options: { + host: { type: 'string' }, port: { type: 'string' }, results: { type: 'string' }, + plans: { type: 'string' }, 'allow-container-bind': { type: 'boolean' }, + } }); + const args: DashboardArgs = { host: values.host ?? '127.0.0.1', + port: values.port === undefined ? 7331 : Number(values.port), + resultsRoot: stackBenchResultsRoot(STACK_BENCH_ROOT, env), + plansRoot: '', allowContainerBind: values['allow-container-bind'] ?? false }; + if (values.results) args.resultsRoot = resolve(values.results); + if (values.plans) args.plansRoot = resolve(values.plans); + args.plansRoot ||= join(args.resultsRoot, 'plans'); + const applianceContainerBind = args.allowContainerBind + && env.STACK_BENCH_APPLIANCE === '1' && args.host === '0.0.0.0'; + if (!LOOPBACK.has(args.host) && !applianceContainerBind) { + throw new Error('dashboard must bind to localhost or a loopback address'); + } + if (!Number.isInteger(args.port) || args.port < 1 || args.port > 65535) { + throw new Error('dashboard port must be an integer from 1 through 65535'); + } + return args; +} + +function json(response: ServerResponse, status: number, value: unknown): void { + const body = Buffer.from(`${JSON.stringify(value)}\n`); + response.writeHead(status, { 'content-type': 'application/json; charset=utf-8', + 'content-length': body.length, 'cache-control': 'no-store' }); + response.end(body); +} + +function securityHeaders(response: ServerResponse): void { + response.setHeader('content-security-policy', "default-src 'self'; connect-src 'self'; img-src 'self' data:; script-src 'self'; style-src 'self'; frame-ancestors 'none'; base-uri 'none'; form-action 'self'"); + response.setHeader('x-content-type-options', 'nosniff'); + response.setHeader('x-frame-options', 'DENY'); + response.setHeader('referrer-policy', 'no-referrer'); +} + +async function body(request: IncomingMessage): Promise { + const chunks: Buffer[] = []; + let bytes = 0; + for await (const chunk of request) { + const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk); + bytes += buffer.length; + if (bytes > 16 * 1024) throw new Error('request body is too large'); + chunks.push(buffer); + } + try { return JSON.parse(Buffer.concat(chunks).toString('utf8')); + } catch { throw new Error('request body must be valid JSON'); } +} + +function createOperationFeed(resultsRoot: string): OperationFeed { + const root = join(resolve(resultsRoot), 'dashboard'); + const path = join(root, 'operations.jsonl'); + mkdirSync(root, { recursive: true }); + return { + path, + append(event: DashboardOperation) { + appendFileSync(path, `${JSON.stringify(event)}\n`, { encoding: 'utf8', mode: 0o600 }); + }, + list() { + const latest = new Map(); + for (const value of readJsonLines(path)) { + const event = dashboardOperation(value); + latest.set(event.id, { ...(latest.get(event.id) ?? {}), ...event }); + } + return [...latest.values()].sort((left, right) => right.updatedAt.localeCompare(left.updatedAt)); + }, + }; +} + +function launchCampaign({ command, jobId, plan, output, operationId, resultsRoot, feed, + env = process.env }: LaunchInput): LaunchChild { + const runtime = controllerRuntimeCommand(command === 'work' + ? ['job', 'work', jobId!, '--results', resultsRoot, '--host', env.STACK_BENCH_HOST_ID ?? 'local'] + : ['campaign', command, plan.path, '--out', output], env); + feed.append({ id: operationId, updatedAt: new Date().toISOString(), + containerName: runtime.containerName, ownershipLabel: runtime.ownershipLabel }); + const operationsRoot = join(resolve(resultsRoot), 'dashboard', 'operations'); + mkdirSync(operationsRoot, { recursive: true }); + const stdoutPath = join(operationsRoot, `${operationId}.stdout.log`); + const stderrPath = join(operationsRoot, `${operationId}.stderr.log`); + const stdout = openSync(stdoutPath, 'a', 0o600); + const stderr = openSync(stderrPath, 'a', 0o600); + let child; + try { + child = spawn(runtime.executable, runtime.args, { + cwd: STACK_BENCH_ROOT, env: runtime.env, stdio: ['ignore', stdout, stderr], windowsHide: true, + }); + } finally { + closeSync(stdout); + closeSync(stderr); + } + child.once('error', error => feed.append({ schemaVersion: 1, id: operationId, + status: 'failed', updatedAt: new Date().toISOString(), error: errorMessage(error) })); + child.once('exit', (code, signal) => feed.append({ schemaVersion: 1, id: operationId, + status: code === 0 ? 'completed' : 'failed', updatedAt: new Date().toISOString(), + exitCode: code, signal })); + return child; +} + +export function createDashboardServer(options: DashboardServerOptions) { + const resultsRoot = resolve(options.resultsRoot); + const plansRoot = resolve(options.plansRoot); + const allowLaunch = options.allowLaunch ?? process.env.STACK_BENCH_APPLIANCE === '1'; + const token = options.token ?? randomBytes(24).toString('base64url'); + const feed = options.feed ?? createOperationFeed(resultsRoot); + const launch = options.launch ?? launchCampaign; + const plans = options.plans ?? (() => discoverPlans(plansRoot)); + const launchReservations = new Set(); + const dispatchJob = (job: ReturnType) => { + const status = readExecutionJob(resultsRoot, job.id); + const key = `job-${job.id}`; + if (status.status === 'queued' && !launchReservations.has(key)) { + launchReservations.add(key); + const now = new Date().toISOString(); + const operation = { schemaVersion: 1, id: randomUUID(), type: 'campaign.run', status: 'running', + createdAt: now, updatedAt: now, actor: 'local-operator', campaignId: job.key, + campaignSha256: job.planSha256, outputName: key }; + feed.append(operation); + try { + const child = launch({ command: 'work', jobId: job.id, + plan: { id: job.key, title: job.key, state: 'frozen', file: 'plan.json', + path: join(resultsRoot, 'jobs', job.id, 'plan.json') }, + output: status.campaignDirectory, operationId: operation.id, resultsRoot, feed }); + child.once('error', () => launchReservations.delete(key)); + child.once('exit', () => launchReservations.delete(key)); + feed.append({ ...operation, pid: child.pid ?? null }); + } catch (error) { + launchReservations.delete(key); + feed.append({ ...operation, status: 'failed', error: errorMessage(error) }); + throw new Error(`Job ${job.id} is saved but dispatch failed. Retry Start with the same setup. ${errorMessage(error)}`); + } + } + return { ...readExecutionJob(resultsRoot, job.id), campaignKey: key }; + }; + const campaignsRoot = join(resultsRoot, 'campaigns'); + const listeners = new Set(); + let watcher: CampaignWatcher | null = null; + let heartbeat: NodeJS.Timeout | null = null; + const broadcast = (change: CampaignChange): void => { + const frame = `event: ${change.type}\ndata: ${JSON.stringify({ key: change.key, + ...(change.attemptId === undefined ? {} : { attemptId: change.attemptId }) })}\n\n`; + for (const listener of listeners) listener.write(frame); + }; + const stopEvents = (): void => { + watcher?.close(); + watcher = null; + if (heartbeat) clearInterval(heartbeat); + heartbeat = null; + }; + const server = createServer(async (request, response) => { + securityHeaders(response); + try { + if (!loopbackHost(request.headers.host)) { + return json(response, 421, { error: 'Dashboard requests must use a loopback host.' }); + } + const url = new URL(request.url ?? '/', `http://${request.headers.host ?? 'localhost'}`); + // The client routes are pages, not fragments: each serves the shell. + const staticFile = STATIC.get(url.pathname) + ?? (SPA_PATH.test(url.pathname) ? STATIC.get('/') : undefined); + if (request.method === 'GET' && staticFile) { + const [file, type] = staticFile; + const path = join(PUBLIC_ROOT, file); + const size = existsSync(path) ? statSync(path).size : 0; + if (!size) return json(response, 404, { error: 'Not found' }); + response.writeHead(200, { 'content-type': type, 'content-length': size, + 'cache-control': file === 'index.html' ? 'no-store' : 'no-cache' }); + createReadStream(path).pipe(response); + return; + } + if (request.method === 'GET' && url.pathname === '/api/run-setup') { + return json(response, 200, runSetupCatalog(resultsRoot)); + } + if (request.method === 'POST' && ['/api/runs/prepare', '/api/runs'].includes(url.pathname)) { + if (!allowLaunch) return json(response, 503, { error: 'Run controls require the appliance.' }); + if (!controlAuthorized(request, request.headers.host, token)) { + return json(response, 403, { error: 'The run request is not authorized.' }); + } + if (!String(request.headers['content-type'] ?? '').toLowerCase().startsWith('application/json')) { + return json(response, 415, { error: 'Run requests must use JSON.' }); + } + try { + const input = await body(request); + if (url.pathname.endsWith('/prepare')) return json(response, 200, prepareRun(resultsRoot, input, options.launch ? process.env : controllerChildEnvironment(process.env))); + // Validate dispatch configuration before publishing a job for workers. + if (!options.launch) controllerRuntimeCommand(['job', 'work'], process.env); + const job = submitPreparedRun(resultsRoot, input, options.launch ? process.env : controllerChildEnvironment(process.env)); + return json(response, 202, dispatchJob(job)); + } catch (error) { return json(response, 400, { error: errorMessage(error) }); } + } + if (request.method === 'GET' && url.pathname === '/api/health') { + return json(response, 200, { ok: true, mode: allowLaunch ? 'controller' : 'read-only' }); + } + if (request.method === 'GET' && url.pathname === '/api/overview') { + return json(response, 200, { campaigns: overviewSummary(campaignsRoot), + canStart: allowLaunch, csrfToken: token }); + } + if (request.method === 'GET' && url.pathname === '/api/session') { + return json(response, 200, { canStart: allowLaunch, csrfToken: token }); + } + if (request.method === 'GET' && url.pathname === '/api/plans') { + return json(response, 200, plans()); + } + const jobRoute = url.pathname.match(/^\/api\/jobs(?:\/([a-f0-9]{64})(?:\/(cancel|start))?)?$/); + if (jobRoute) { + const id = jobRoute[1], cancel = jobRoute[2] !== undefined; + if (request.method === 'GET' && !cancel) { + if (!id) { + const after = url.searchParams.get('after') ?? ''; + const limit = Number(url.searchParams.get('limit') ?? 50); + if ((after && !/^[a-f0-9]{64}$/.test(after)) || !Number.isSafeInteger(limit) || limit < 1 || limit > 200) { + return json(response, 400, { error: 'Use a valid job cursor and a page size from 1 through 200.' }); + } + return json(response, 200, listExecutionJobs(resultsRoot, { after, limit })); + } + if (!existsSync(join(resultsRoot, 'jobs', id, 'job.json'))) return json(response, 404, { error: 'Job not found.' }); + return json(response, 200, readExecutionJob(resultsRoot, id)); + } + if (request.method === 'POST' && (!id || cancel)) { + if (!allowLaunch) return json(response, 503, { error: 'Run controls are available inside the Stack Bench appliance.' }); + if (!controlAuthorized(request, request.headers.host, token)) { + return json(response, 403, { error: 'The job request is not authorized.' }); + } + if (id) { + if (!existsSync(join(resultsRoot, 'jobs', id, 'job.json'))) return json(response, 404, { error: 'Job not found.' }); + if (jobRoute[2] === 'start') { + if (!options.launch) controllerRuntimeCommand(['job', 'work'], process.env); + return json(response, 202, dispatchJob(readExecutionJob(resultsRoot, id).job)); + } + cancelExecutionJob(resultsRoot, id); + return json(response, 202, readExecutionJob(resultsRoot, id)); + } + if (!String(request.headers['content-type'] ?? '').toLowerCase().startsWith('application/json')) { + return json(response, 415, { error: 'Job submissions must use JSON.' }); + } + try { + const job = submitExecutionJob(resultsRoot, await body(request)); + return json(response, 202, readExecutionJob(resultsRoot, job.id)); + } catch (error) { return json(response, 400, { error: errorMessage(error) }); } + } + } + if (request.method === 'GET' && url.pathname === '/api/events') { + response.writeHead(200, { 'content-type': 'text/event-stream; charset=utf-8', + 'cache-control': 'no-store', connection: 'keep-alive' }); + response.write(': open\n\n'); + listeners.add(response); + watcher ??= watchCampaigns(campaignsRoot, broadcast, + mode => console.log(`Stack Bench dashboard: campaign watcher ${mode}`)); + // A silent connection is dropped by proxies long before a campaign + // writes anything. + heartbeat ??= setInterval(() => { + for (const listener of listeners) listener.write(': ping\n\n'); + }, HEARTBEAT_MS).unref(); + request.once('close', () => { + listeners.delete(response); + if (!listeners.size) stopEvents(); + }); + return; + } + const timeRoute = url.pathname.match(/^\/api\/campaigns\/([^/]+)\/attempts\/([^/]+)\/time$/); + if (timeRoute && (request.method === 'GET' || request.method === 'POST')) { + const key = decodeURIComponent(timeRoute[1] ?? ''); + if (!SAFE_NAME.test(key)) return json(response, 400, { error: 'The campaign name is invalid.' }); + const directory = contained(campaignsRoot, key, 'campaign'); + const attemptId = decodeURIComponent(timeRoute[2] ?? ''); + if (request.method === 'GET') return json(response, 200, readCampaignTimeBudget(directory, attemptId)); + if (!allowLaunch) return json(response, 503, { error: 'Run controls are available inside the Stack Bench appliance.' }); + if (!controlAuthorized(request, request.headers.host, token)) { + return json(response, 403, { error: 'The time request is not authorized.' }); + } + const input = await body(request) as { minutes?: unknown; grantId?: unknown } | null; + if (!input || typeof input.minutes !== 'number' || !Number.isSafeInteger(input.minutes * 60_000) + || !Number.isInteger(input.minutes) || input.minutes <= 0 || typeof input.grantId !== 'string') { + return json(response, 400, { error: 'Positive whole minutes and a grant ID are required.' }); + } + try { + const receipt = requestCampaignTimeGrant(directory, { + attemptId, grantId: input.grantId, minutes: input.minutes, + }); + return json(response, receipt.disposition === 'rejected' ? 409 : 202, + receipt.disposition === 'rejected' ? { ...receipt, error: receipt.reason } : receipt); + } catch (error) { + return json(response, 409, { error: errorMessage(error) }); + } + } + const stopRoute = url.pathname.match(/^\/api\/campaigns\/([^/]+)\/stop$/); + if (request.method === 'POST' && stopRoute) { + if (!allowLaunch) return json(response, 503, { error: 'Run controls are available inside the Stack Bench appliance.' }); + if (!controlAuthorized(request, request.headers.host, token)) { + return json(response, 403, { error: 'The stop request is not authorized.' }); + } + const key = decodeURIComponent(stopRoute[1] ?? ''); + if (!SAFE_NAME.test(key)) return json(response, 400, { error: 'The campaign name is invalid.' }); + const input = await body(request); + const owner = input && typeof input === 'object' && 'owner' in input ? input.owner : null; + if (typeof owner !== 'string' || !/^[a-f0-9]{64}$/.test(owner)) { + return json(response, 400, { error: 'The current controller identity is required.' }); + } + const directory = contained(campaignsRoot, key, 'campaign'); + const campaign = summarizeCampaign(directory, { includeAttempts: false }); + if (!requestCampaignCancellation(directory, + { id: campaign.id, contentSha256: campaign.sha256 }, owner)) { + return json(response, 409, { error: 'The controller changed or stopped. Refresh the campaign.' }); + } + const now = new Date().toISOString(); + const operation = { id: randomUUID(), type: 'campaign.stop', status: 'requested', + updatedAt: now, campaignId: campaign.id, outputName: key, owner }; + feed.append(operation); + return json(response, 202, operation); + } + const resumeRoute = url.pathname.match(/^\/api\/campaigns\/([^/]+)\/resume$/); + if (request.method === 'POST' && resumeRoute) { + if (!allowLaunch) return json(response, 503, { error: 'Run controls are available inside the Stack Bench appliance.' }); + if (!controlAuthorized(request, request.headers.host, token)) { + return json(response, 403, { error: 'The run request is not authorized.' }); + } + const key = decodeURIComponent(resumeRoute[1] ?? ''); + if (!SAFE_NAME.test(key)) return json(response, 400, { error: 'The campaign name is invalid.' }); + const campaign = summarizeCampaign( + contained(join(resultsRoot, 'campaigns'), key, 'campaign'), { includeAttempts: false }); + const priorExecutions = campaign.summary?.executions ?? 0; + if (campaign.mode !== 'dependency' || campaign.status !== 'prepared' || priorExecutions < 1) { + return json(response, 409, { error: 'Only an interrupted campaign that is ready can resume.' }); + } + const plan = plans().find(item => item.id === campaign.id && item.sha256 === campaign.sha256); + if (!plan || plan.state !== 'frozen') { + return json(response, 409, { error: 'The test plan used by this campaign is unavailable.' }); + } + const reservation = `${campaign.id}:${campaign.sha256}:${key}`; + if (launchReservations.has(reservation)) { + return json(response, 409, { error: 'This campaign already has an active controller.' }); + } + launchReservations.add(reservation); + const now = new Date().toISOString(); + const operation = { schemaVersion: 1, id: randomUUID(), type: 'campaign.resume', + status: 'running', createdAt: now, updatedAt: now, actor: 'local-operator', + campaignId: campaign.id, campaignSha256: campaign.sha256, outputName: key }; + feed.append(operation); + const output = join(resultsRoot, 'campaigns', key); + try { + const child = launch({ command: 'resume', plan: { ...plan, path: join(plansRoot, plan.file) }, output, + operationId: operation.id, resultsRoot, feed, env: process.env }); + if (typeof child?.once === 'function') { + child.once('error', () => launchReservations.delete(reservation)); + child.once('exit', () => launchReservations.delete(reservation)); + } else { + launchReservations.delete(reservation); + } + feed.append({ ...operation, pid: child?.pid ?? null }); + } catch (error) { + launchReservations.delete(reservation); + feed.append({ schemaVersion: 1, id: operation.id, status: 'failed', + updatedAt: new Date().toISOString(), error: errorMessage(error) }); + throw error; + } + return json(response, 202, operation); + } + const artifactRoute = url.pathname.match(/^\/api\/campaigns\/([^/]+)\/artifacts\/([^/]+)$/); + if (request.method === 'GET' && artifactRoute) { + let artifact; + try { + artifact = resolveCampaignArtifact(resultsRoot, decodeURIComponent(artifactRoute[1] ?? ''), + decodeURIComponent(artifactRoute[2] ?? '')); + } catch { + return json(response, 404, { error: 'Campaign artifact not found.' }); + } + const body = readCampaignArtifactBody(artifact); + const download = url.searchParams.get('download') === '1'; + const type = artifact.kind === 'visual' ? artifact.contentType + : artifact.kind === 'report' && !download ? 'text/html; charset=utf-8' + : 'text/plain; charset=utf-8'; + if (artifact.kind === 'report' && !download) { + response.setHeader('content-security-policy', "sandbox; default-src 'none'; style-src 'unsafe-inline'; img-src data:"); + } + response.writeHead(200, { 'content-type': type, 'content-length': body.length, + 'cache-control': 'no-store', 'content-disposition': `${download ? 'attachment' : 'inline'}; filename*=UTF-8''${encodeURIComponent(basename(artifact.path))}` }); + response.end(body); + return; + } + const campaignRoute = url.pathname.match(/^\/api\/campaigns\/([^/]+)(?:\/(.*))?$/); + if (request.method === 'GET' && campaignRoute) { + const key = decodeURIComponent(campaignRoute[1] ?? ''); + const rest = campaignRoute[2] ?? ''; + if (!SAFE_NAME.test(key)) { + return json(response, 400, { error: 'The campaign name is invalid.' }); + } + if (!rest && /^job-[a-f0-9]{64}$/.test(key) + && !existsSync(join(campaignsRoot, key, 'state.json')) + && existsSync(join(resultsRoot, 'jobs', key.slice(4), 'job.json'))) { + const pendingJob = readExecutionJob(resultsRoot, key.slice(4)); + const operation = feed.list().find(op => op.outputName === key); + return json(response, 200, { pendingJob, dispatchError: operation?.status === 'failed' ? operation.error ?? 'Worker exited before campaign startup.' : null }); + } + if (!existsSync(contained(campaignsRoot, key, 'campaign'))) { + return json(response, 404, { error: 'Not found' }); + } + const attemptRoute = rest.match(/^attempts\/([^/]+)\/(checks|package|log|transcript)$/); + const attemptId = attemptRoute ? decodeURIComponent(attemptRoute[1] ?? '') : ''; + if (attemptRoute && !SAFE_NAME.test(attemptId)) { + return json(response, 400, { error: 'The attempt name is invalid.' }); + } + const from = url.searchParams.get('from') ?? '0'; + if (attemptRoute?.[2] === 'log' && (!/^\d+$/.test(from) || !Number.isSafeInteger(Number(from)))) { + return json(response, 400, { error: 'The log offset must be a whole number of bytes.' }); + } + try { + if (!rest) return json(response, 200, await campaignLiveSheet(resultsRoot, key)); + if (rest === 'live') return json(response, 200, campaignLiveUpdate(resultsRoot, key)); + if (rest === 'progression') { + const progression = await campaignLiveProgression(resultsRoot, key); + return progression + ? json(response, 200, progression) + : json(response, 404, { error: 'Progression is recorded for dependency campaigns only.' }); + } + if (attemptRoute?.[2] === 'transcript') { + const before = url.searchParams.get('before'); + if (before !== null && (!/^\d+$/.test(before) || !Number.isSafeInteger(Number(before)))) { + return json(response, 400, { error: 'Invalid transcript offset' }); + } + return json(response, 200, await attemptTranscript(resultsRoot, key, attemptId, + url.searchParams.get('session') ?? '', before === null ? undefined : Number(before))); + } + if (attemptRoute?.[2] === 'checks') { + return json(response, 200, attemptChecks(resultsRoot, key, attemptId)); + } + if (attemptRoute?.[2] === 'package') { + return json(response, 200, attemptPackage(resultsRoot, key, attemptId)); + } + if (attemptRoute) { + const slice = attemptLogSlice(resultsRoot, key, attemptId, Number(from)); + const text = Buffer.from(slice.text); + response.writeHead(200, { 'content-type': 'text/plain; charset=utf-8', + 'content-length': text.length, 'cache-control': 'no-store', + 'x-stack-bench-log-offset': String(slice.offset) }); + response.end(text); + return; + } + } catch (error) { + if (error instanceof Error && error.message === 'campaign attempt does not exist') { + return json(response, 404, { error: 'Not found' }); + } + return json(response, 422, { error: `Cannot read campaign evidence: ${errorMessage(error)}` }); + } + return json(response, 404, { error: 'Not found' }); + } + return json(response, 404, { error: 'Not found' }); + } catch (error) { + return json(response, 500, { error: errorMessage(error) }); + } + }); + // An open event stream is not an idle connection: the watchers stop and the + // streams end as the server closes, not once it has. + const closeServer = server.close.bind(server); + server.close = ((callback?: (error?: Error) => void) => { + stopEvents(); + for (const listener of listeners) listener.end(); + listeners.clear(); + return closeServer(callback); + }) as typeof server.close; + return { server, token, allowLaunch }; +} + +async function main() { + const args = parseDashboardArgs(process.argv); + const { server, allowLaunch } = createDashboardServer(args); + await new Promise((resolveListen, reject) => { + server.once('error', reject); + server.listen(args.port, args.host, resolveListen); + }); + console.log(`Stack Bench dashboard: http://${args.host}:${args.port} (${allowLaunch ? 'controller' : 'read-only'})`); +} + +if (import.meta.url === pathToFileURL(process.argv[1] ?? '').href) { + main().catch(error => { console.error(`stack-bench-dashboard: ${errorMessage(error)}`); process.exitCode = 2; }); +} diff --git a/tools/stack-bench/dashboard/dashboard-transcript.ts b/tools/stack-bench/dashboard/dashboard-transcript.ts new file mode 100644 index 00000000000..51a8459a332 --- /dev/null +++ b/tools/stack-bench/dashboard/dashboard-transcript.ts @@ -0,0 +1,180 @@ +import { sha256 } from '../src/evidence/provenance.js'; +import { loadTrack, workDirFor } from '../src/composition/tracks.js'; +import { execFile } from 'node:child_process'; +import { open, readdir, realpath, stat } from 'node:fs/promises'; +import { existsSync, realpathSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { dirname, join, relative, resolve, sep } from 'node:path'; +import { CODING_PROVIDERS } from '../container/coding-providers.js'; +import { CONTAINER_CLAUDE_TRANSCRIPT_READ } from '../container/claude-transcript-reader.js'; +import { AGENT_ADAPTER_REGISTRY } from '../src/agents/agent-adapters.js'; +import type { PublicBackendLease } from '../src/runtime/backend-lease.js'; +import { publicBackendLease, readBackendLease } from '../src/runtime/backend-lease.js'; +import { readArtifactPayload } from '../src/evidence/artifacts.js'; +import { codingContainerAgentExecOptions } from '../src/runtime/coding-container-policy.js'; +import { inspectBuildContainer } from '../src/stacks/hosted-lifecycle.js'; +import { redactCredentials } from '../src/evidence/diagnostic-sanitizer.js'; + +export interface TranscriptMessage { id: string; role: string; text: string; tool: boolean } +export interface TranscriptPage { + sessions: Array<{ id: string; label: string }>; + session: string; + before: number | null; + messages: TranscriptMessage[]; + skipped: number; +} +const record = (value: unknown): value is Record => + !!value && typeof value === 'object' && !Array.isArray(value); + +export function transcriptMessages(text: string): { messages: TranscriptMessage[]; skipped: number } { + const messages: TranscriptMessage[] = []; + let skipped = 0; + let eventId = ''; + let blockIndex = 0; + const add = (role: string, value: unknown, tool = false) => { + if (typeof value === 'string' && value.trim()) messages.push({ id: `${eventId}-${blockIndex++}`, role, + text: redactCredentials(value), tool }); + }; + for (const line of text.split('\n').filter(line => line.trim())) { + eventId = sha256(line); + blockIndex = 0; + let event: unknown; + try { event = JSON.parse(line); } catch { skipped++; continue; } + if (!record(event)) continue; + const message = record(event.message) ? event.message + : event.type === 'response_item' && record(event.payload) ? event.payload : null; + if (message) { + const role = String(message.role ?? event.type ?? 'Agent'); + if (typeof message.content === 'string') add(role, message.content); + if (Array.isArray(message.content)) for (const block of message.content) { + if (!record(block)) continue; + if (['text', 'input_text', 'output_text'].includes(String(block.type))) add(role, block.text); + if (block.type === 'tool_use') add(String(block.name ?? 'Tool'), JSON.stringify(block.input, null, 2), true); + if (block.type === 'tool_result') add('Tool result', typeof block.content === 'string' + ? block.content : JSON.stringify(block.content, null, 2), true); + } + if (message.type === 'function_call') add(String(message.name ?? 'Tool'), message.arguments, true); + if (message.type === 'function_call_output') add('Tool result', message.output, true); + } + if (event.type === 'item.completed' && record(event.item)) { + const item = event.item; + if (item.type === 'agent_message') add('assistant', item.text); + if (item.type === 'command_execution') add('Command', `${item.command ?? ''}\n${item.aggregated_output ?? ''}`, true); + if (item.type === 'file_change') add('File changes', JSON.stringify(item.changes, null, 2), true); + } + } + return { messages, skipped }; +} + +export interface TranscriptFile { + id: string; + label: string; + size: number; + modified: number; + read(start: number, count: number): Promise; +} +const pendingReads = new Map>(); +function dockerRead(args: string[]): Promise { + const key = JSON.stringify(args); + const pending = pendingReads.get(key); + if (pending) return pending; + const result = new Promise((resolve, reject) => { + execFile('docker', args, { timeout: 5_000, maxBuffer: 2 * 1024 * 1024, encoding: 'buffer' }, + (error, stdout) => error ? reject(error) : resolve(stdout)); + }).finally(() => pendingReads.delete(key)); + pendingReads.set(key, result); + return result; +} + +export function transcriptLease(directory: string, runtimeRoot = process.env.STACK_BENCH_RUNTIME_DIR + ?? join(tmpdir(), 'stack-bench-runtime')): PublicBackendLease | null { + const evidence = join(directory, 'backend-lease.json'); + if (existsSync(evidence)) return readArtifactPayload(evidence, + { expectedKind: 'backend_lease_evidence' }); + const runPath = join(directory, 'run.json'); + if (!existsSync(runPath)) return null; + const initial = readArtifactPayload<{ backendLease?: PublicBackendLease }>(runPath, + { expectedKind: 'benchmark_run' }).backendLease; + if (!initial) return null; + if (!/^[a-zA-Z0-9][a-zA-Z0-9._-]*$/.test(initial.runId)) throw new Error('Invalid transcript run identity'); + const runtime = resolve(runtimeRoot, initial.runId); + const path = join(runtime, 'backend-lease.json'); + if (!existsSync(path)) return null; + if (dirname(realpathSync(runtime)) !== realpathSync(resolve(runtimeRoot)) + || dirname(realpathSync(path)) !== realpathSync(runtime)) throw new Error('Transcript lease is outside runtime directory'); + const current = publicBackendLease(readBackendLease(path, { runId: initial.runId, backend: initial.backend, active: true })); + if (current.ownership.markerSha256 !== initial.ownership?.markerSha256 + || current.track !== initial.track || current.runIndex !== initial.runIndex) { + throw new Error('Transcript lease ownership changed'); + } + return current; +} + +// Reads only this attempt's transcript mounts. Never scans another account's sessions. +export async function attemptTranscriptFiles(executions: Array<{ directory: string; label: string }>, + adapterId: string): Promise { + const provider = AGENT_ADAPTER_REGISTRY.get(adapterId).provider; + if (!provider || !(provider in CODING_PROVIDERS)) return []; + const config = CODING_PROVIDERS[provider as keyof typeof CODING_PROVIDERS]; + const files: TranscriptFile[] = []; + for (const execution of executions) { + const lease = transcriptLease(execution.directory); + if (!lease) continue; + const root = config.projects(join(workDirFor(loadTrack(lease.track), lease.backend, lease.runIndex, lease.runId), 'app')); + let remote: ((name: string, start: number, count: number) => Promise) | null = null; + if (lease.state === 'active' && lease.resources.buildContainer?.owned) { + const actual = await dockerRead(['inspect', '--format', '{{.Id}}', lease.resources.buildContainer.name]); + const container = inspectBuildContainer(lease, () => actual.toString()); + remote = (name, start, count) => dockerRead(['exec', ...codingContainerAgentExecOptions(), + container.id, 'node', '-e', CONTAINER_CLAUDE_TRANSCRIPT_READ, + config.containerTranscripts, name, String(start), String(count)]); + } + let entries: Array<[string, number, number]>; + if (remote) entries = JSON.parse((await remote('', 0, 0)).toString()) as Array<[string, number, number]>; + else { + if (!existsSync(root)) continue; + const resolvedRoot = await realpath(root); + entries = []; + for (const entry of await readdir(root, { recursive: true, withFileTypes: true })) { + if (!entry.isFile() || !entry.name.endsWith('.jsonl')) continue; + const path = join(entry.parentPath, entry.name); + if (!(await realpath(path)).startsWith(resolvedRoot + sep)) continue; + const info = await stat(path); + entries.push([relative(root, path), info.size, info.mtimeMs]); + } + } + for (const [name, size, modified] of entries) { + const reader = remote; + files.push({ id: Buffer.from(`${execution.label}/${name}`).toString('base64url'), + label: `${execution.label} / ${new Date(modified).toISOString().replace('T', ' ').slice(0, 16)} UTC`, size, modified, + read: async (start, count) => { + if (!Number.isSafeInteger(start) || start < 0 || !Number.isSafeInteger(count) + || count < 0 || count > 256 * 1024) throw new Error('Invalid transcript range'); + if (reader) return reader(name, start, count); + const path = join(root, name); + if (!(await realpath(path)).startsWith(await realpath(root) + sep)) { + throw new Error('transcript is outside the attempt directory'); + } + const fd = await open(path, 'r'), buffer = Buffer.alloc(count); + try { return buffer.subarray(0, (await fd.read(buffer, 0, count, start)).bytesRead); } + finally { await fd.close(); } + } }); + } + } + return files.sort((a, b) => a.modified - b.modified); +} +export async function readAttemptTranscript(executions: Array<{ directory: string; label: string }>, + adapterId: string, session = '', before?: number): Promise { + const files = await attemptTranscriptFiles(executions, adapterId); + const file = (session ? files.find(file => file.id === session) : files.at(-1)); + if (session && !file) throw new Error('Transcript session not found'); + if (!file) return { sessions: [], session: '', before: null, messages: [], skipped: 0 }; + const end = Math.min(before ?? file.size, file.size); + const start = Math.max(0, end - 256 * 1024); + const bytes = await file.read(start, end - start); + const first = start ? bytes.indexOf(10) + 1 : 0; + const last = bytes.lastIndexOf(10); + const content = last >= first ? bytes.subarray(first, last + 1).toString('utf8') : ''; + return { sessions: files.map(({ id, label }) => ({ id, label })), session: file.id, + before: start > 0 ? start + first : null, ...transcriptMessages(content) }; +} diff --git a/tools/stack-bench/dashboard/dashboard-views.ts b/tools/stack-bench/dashboard/dashboard-views.ts new file mode 100644 index 00000000000..ca9d5ab9e9b --- /dev/null +++ b/tools/stack-bench/dashboard/dashboard-views.ts @@ -0,0 +1,1031 @@ +import { readAttemptTranscript } from './dashboard-transcript.js'; +import { liveCostTotal, liveTranscriptCost } from './dashboard-live-cost.js'; +import { canonicalDefinitionJson } from '../src/composition/definition-plan.js'; +import { sha256 } from '../src/evidence/provenance.js'; +import { closeSync, existsSync, fstatSync, openSync, readFileSync, readSync, readdirSync, statSync } + from 'node:fs'; +import { basename, join, resolve } from 'node:path'; + +import type { CampaignAttemptState } from '../src/campaigns/campaign-scheduler.js'; +import type { DependencyPromptSelection, DependencyState } + from '../src/progression/dependency-mode.js'; +import type { ProgressionState } from '../src/progression/progression-state.js'; +import type { CompiledCampaignPlan } from '../src/campaigns/campaign-compiler.js'; +import type { DependencyProgress } from '../src/campaigns/campaign-inspection.js'; +import type { GradeBundlePayload } from '../src/evidence/benchmark-run.js'; +import { executionSpend } from '../src/campaigns/campaign-report.js'; +import type { CostEvidence } from '../src/evidence/cost-proof.js'; +import type { RunCheckpoint } from '../src/evidence/run-checkpoints.js'; +import { scoreDependencyState, dependencyCompletionBreakdown, type DependencyCompletionBreakdown } from '../src/progression/dependency-score.js'; +import type { CheckCompletion } from '../src/evidence/check-completion.js'; +import { ARTIFACT_FILE, readArtifact, readArtifactPayload } from '../src/evidence/artifacts.js'; +import { CAMPAIGN_FILE } from '../src/campaigns/campaign-path.js'; +import { campaignFacts, inspectCampaignAttempt } from '../src/campaigns/campaign-inspection.js'; +import { campaignLockIsActive, readCampaignLock } from '../src/campaigns/campaign-lock.js'; +import { campaignProgressionOwner } from '../src/campaigns/campaign-compiler.js'; +import { compileProgressionInput, dependencyRuntimeDefinition } + from '../src/progression/progression-definition.js'; +import { progressionEngine } from '../src/progression/progression-engine.js'; +import { readCampaignState } from '../src/campaigns/campaign-scheduler.js'; +import { readProgressionState } from '../src/progression/progression-state.js'; +import { redactCredentials } from '../src/evidence/diagnostic-sanitizer.js'; +import { CHECK_EVIDENCE_STATUSES, evidenceDisposition, type CheckEvidence } from '../src/evidence/check-evidence.js'; +import { repairBudgetLimit, type RepairBudget } from '../src/progression/repair-plan.js'; +import { MAX_LOG_BYTES, contained, parseRunProgress, readTextTail, attemptPause, + walkPublicExecutionArtifacts } from './dashboard-model.js'; +import type { DashboardArtifact } from './dashboard-model.js'; +import { attemptExcluded, attemptMetrics, attemptStalling, compareCampaign, median } + from './public/metrics.js'; + +const CAMPAIGN_KEY = /^[a-z0-9][a-z0-9.-]*$/; +const GRADE_DIRECTORY = /^(?:first-build-l(\d+)-grading|l(\d+)-fix(\d+)-grading|grading)$/i; +const PROGRESSION_ATTEMPT = /^attempt-(\d+)$/i; +const LOG_FILE = 'process.stdout.log'; + +type ControllerActive = (directory: string, campaign: CompiledCampaignPlan) => boolean; +type InspectedAttempt = ReturnType; + +interface ViewOptions { + controllerActive?: ControllerActive; +} + +function errorMessage(error: unknown): string { + return error instanceof Error ? error.message : String(error); +} + +function percentage(value: number | null | undefined): number | null { + return value == null ? null : Math.round(value * 1000) / 10; +} + +function campaignDirectory(resultsRoot: string, key: string): string { + if (!CAMPAIGN_KEY.test(key)) throw new Error('campaign key is invalid'); + return contained(join(resolve(resultsRoot), 'campaigns'), key, 'campaign'); +} + +function fileFingerprint(path: string): string | null { + if (!existsSync(path)) return null; + const stat = statSync(path); + return `${stat.size}:${stat.mtimeMs}`; +} + +const campaignStateCache = new Map; +}>(); + +// Share frozen plan/state validation across dashboard resources. Execution +// evidence and controller liveness keep their own freshness checks. +function dashboardCampaignState(directory: string): ReturnType { + const fingerprint = [CAMPAIGN_FILE.plan, CAMPAIGN_FILE.state] + .map(file => fileFingerprint(join(directory, file))).join('|'); + const cached = campaignStateCache.get(directory); + if (cached?.fingerprint === fingerprint) return cached.value; + const value = readCampaignState(directory, { requireCurrentInputs: false }); + campaignStateCache.set(directory, { fingerprint, value }); + return value; +} + +// Every file whose change can move a number in the view, and nothing else: a +// running campaign that has written nothing since the last read is unchanged. +function executionFingerprints(directory: string, files: readonly string[]): string[] { + const attemptsRoot = join(directory, 'attempts'); + if (!existsSync(attemptsRoot)) return []; + const parts: string[] = []; + for (const attempt of readdirSync(attemptsRoot, { withFileTypes: true })) { + if (!attempt.isDirectory()) continue; + const attemptDirectory = join(attemptsRoot, attempt.name); + for (const execution of readdirSync(attemptDirectory, { withFileTypes: true })) { + if (!execution.isDirectory()) continue; + for (const file of files) { + const stamp = fileFingerprint(join(attemptDirectory, execution.name, file)); + if (stamp) parts.push(`${attempt.name}/${execution.name}/${file}:${stamp}`); + } + } + } + return parts.sort(); +} + +function campaignFingerprint(directory: string, files: readonly string[], + executionFiles: readonly string[]): string { + return [...files.map(file => `${file}:${fileFingerprint(join(directory, file)) ?? 'missing'}`), + ...executionFingerprints(directory, executionFiles)].join('|'); +} + +// Overview + +export interface OverviewCampaign { + key: string; + id: string; + title: string; + status: string; + mode: string; + levels: number[]; + repetitions: number; + provisional: boolean; + updatedAt: string | null; + // The mode's official score per stack, as a percentage; null until a stack + // has a comparable result. + scores: Record; + attempts: { total: number; running: number; completed: number }; +} + +export interface UnreadableOverviewCampaign { + key: string; + id: string; + title: string; + status: 'unreadable'; + error: string; +} + +export type OverviewEntry = OverviewCampaign | UnreadableOverviewCampaign; + +const overviewCache = new Map(); + +function overviewCampaign(directory: string): { + plan: CompiledCampaignPlan; + campaign: OverviewCampaign; +} { + const { plan, state } = dashboardCampaignState(directory); + const attempts = state.attempts.map(attempt => + inspectCampaignAttempt(plan, attempt, directory)); + const comparison = compareCampaign({ attempts }); + const scores = Object.fromEntries(plan.stacks.map(stack => + [stack.id, percentage(comparison.rows.find(row => row.stack === stack.id)?.final ?? null)])); + return { + plan, + campaign: { + key: basename(resolve(directory)), + id: plan.id, + title: plan.title, + status: state.status, + mode: plan.definition.mode?.id ?? 'sequential', + levels: plan.definition.levels, + repetitions: plan.definition.repetitions, + provisional: campaignFacts(plan).grading.status !== 'qualified', + updatedAt: state.updatedAt, + scores, + attempts: { total: state.summary.total, running: state.summary.running, + completed: state.summary.completed }, + }, + }; +} + +// Liveness is one more fact about a running campaign, not a condition of +// reading it: the read-only host view has no Docker socket to ask. +function controllerInterrupted(probe: ControllerActive, directory: string, + plan: CompiledCampaignPlan, status: string): boolean { + if (status !== 'running') return false; + try { return !probe(directory, plan); } catch { return false; } +} + +function withInterruption(campaign: OverviewCampaign, interrupted: boolean): OverviewCampaign { + if (!interrupted) return campaign; + return { ...campaign, status: 'attention-required', + attempts: { ...campaign.attempts, running: 0 } }; +} + +// Summaries only: no attempt list, no log, no plan. The fingerprint covers a +// running campaign too, so a poll that finds nothing changed costs one stat +// per evidence file instead of a full replay. +export function overviewSummary(campaignsRoot: string, + { controllerActive = campaignLockIsActive }: ViewOptions = {}): OverviewEntry[] { + if (!existsSync(campaignsRoot)) return []; + const campaigns: OverviewEntry[] = []; + for (const entry of readdirSync(campaignsRoot, { withFileTypes: true })) { + if (!entry.isDirectory()) continue; + const directory = join(campaignsRoot, entry.name); + if (!existsSync(join(directory, CAMPAIGN_FILE.state)) + || !existsSync(join(directory, CAMPAIGN_FILE.plan))) continue; + try { + const fingerprint = campaignFingerprint(directory, + [CAMPAIGN_FILE.plan, CAMPAIGN_FILE.state], [ARTIFACT_FILE.run]); + const cached = overviewCache.get(directory); + const fresh = cached?.fingerprint === fingerprint + ? { plan: cached.plan, campaign: cached.campaign } : overviewCampaign(directory); + overviewCache.set(directory, { fingerprint, ...fresh }); + campaigns.push(withInterruption(fresh.campaign, controllerInterrupted(controllerActive, + directory, fresh.plan, fresh.campaign.status))); + } catch (error) { + campaigns.push({ key: entry.name, id: entry.name, title: entry.name, + status: 'unreadable', error: errorMessage(error) }); + } + } + return campaigns.sort((left, right) => + String('updatedAt' in right ? right.updatedAt ?? '' : '') + .localeCompare(String('updatedAt' in left ? left.updatedAt ?? '' : ''))); +} + +// Campaign sheet + +export interface SheetFacts { + mode: string; + workSelection: string | null; + repairSelection: string | null; + repairLimits: RepairBudget; + agent: string | null; + model: string | null; + guidance: string | null; + productionQuality: boolean | null; + recipes: Array<{ level: number; id: string | null; contentSha256: string | null }>; + timeLimitMinutes: number; + spendLimitUsd: number | null; + controllerImage: string | null; + buildImage: string | null; + planSha256: string; + grading: string; + gradingReasons: string[]; +} + +export interface ClimbPoint { + score: number; + max: number; + level: number | null; + unaided: boolean; +} + +export interface SheetAttempt { + model?: string; + effort?: string; + liveSpend?: number; + id: string; + repetition: number; + status: string; + phase: string; + stalling: boolean; + excluded: string | null; + continued: boolean; + logUpdatedAt: string | null; + activityUpdatedAt?: string | null; + paused?: boolean; + score: number | null; + unaided: number | null; + repairs: { used: number; budget: number }; + timeSec: number | null; + executionStartedAt: string | null; + executionCompletedAt: string | null; + executionCost?: CostEvidence; + spend: CostEvidence; + spendPending: boolean; + completion: CheckCompletion | null; + featureCompletion?: DependencyCompletionBreakdown['featureCompletion'] | null; + checkCategories?: DependencyCompletionBreakdown['checkCategories'] | null; + variant: string; + climb: ClimbPoint[]; +} + +export interface SheetLevel { + level: number; + unaided: { score: number; max: number } | null; + score: { score: number; max: number } | null; + repairs: number; +} + +export interface SheetQuestline { + id: string; + title: string; + score: number | null; + nodes: Array<{ id: string; status: string }>; +} + +export interface SheetStack { + liveSpend?: number; + stack: string; + costPerValidRun: number | null; + selectedAttemptId: string | null; + score: number | null; + points: { score: number; max: number } | null; + unaided: number | null; + continued: boolean; + regressions: number | null; + timeSec: number | null; + spend: CostEvidence; + spendPending: boolean; + completionRate: number | null; + n: number; + attempts: SheetAttempt[]; + levels: SheetLevel[] | null; + questlines: SheetQuestline[] | null; +} + +export interface CampaignSheet { + key: string; + id: string; + title: string; + status: string; + mode: string; + levels: number[]; + repetitions: number; + provisional: boolean; + mixedScope: boolean; + executions: number; + // A dependency campaign that stopped between executions is the one thing an + // operator can restart; the server checks the same three facts again. + resumable: boolean; + controllerOwner?: string | null; + reportFiles?: string[]; + createdAt: string; + updatedAt: string; + facts: SheetFacts; + stacks: SheetStack[]; +} + +interface SheetAttemptView { + inspected: InspectedAttempt; + attempt: SheetAttempt; +} + +function sheetFacts(plan: CompiledCampaignPlan): SheetFacts { + const mode = plan.definition.mode; + const policy = plan.dependencyPolicy?.definition ?? null; + const agent = plan.agents[0] ?? null; + const facts = campaignFacts(plan); + return { + mode: mode.id, + workSelection: policy?.workSelection ?? mode.workSelection ?? null, + repairSelection: policy?.repair.selection ?? plan.definition.repair.selection, + repairLimits: plan.definition.repair.budget, + agent: agent?.adapter ?? null, + model: agent?.model ?? null, + guidance: plan.attempts[0]?.guidance ?? null, + productionQuality: plan.attempts.every(attempt => attempt.condition.productionQuality === true) + ? true : plan.attempts.some(attempt => attempt.condition.productionQuality === true) ? null : false, + recipes: facts.recipes, + timeLimitMinutes: plan.definition.budgets.attemptTimeoutMinutes, + spendLimitUsd: plan.definition.budgets.maxCostUsdPerAttempt, + controllerImage: facts.runtime.controllerImage, + buildImage: facts.runtime.buildImage, + planSha256: plan.contentSha256, + grading: gradingStatus(facts.grading), + gradingReasons: [...new Set(facts.grading.levels.flatMap(level => level.reasons ?? []))], + }; +} + +// A campaign whose levels disagree is partly publishable and says so. +function gradingStatus(grading: ReturnType['grading']): string { + const levels = new Set(grading.levels.map(level => level.status)); + return levels.size > 1 ? 'partial' : grading.status; +} + +function dependencyRepairs(plan: CompiledCampaignPlan, + dependency: DependencyProgress): { used: number; budget: number } { + return { + used: dependency.history?.repairAttempts ?? 0, + budget: repairBudgetLimit(plan.definition.repair, { + features: dependency.nodes.length, + depths: plan.definition.levels.length, + }), + }; +} + +function attemptRegressions(attempt: InspectedAttempt): number { + if (attempt.dependency) return attempt.dependency.regressions ?? 0; + return (attempt.result?.levels ?? []).reduce((total, level) => total + level.regressions, 0); +} + +// Continued: the attempt resumed on a repair grant, so its first grade is a +// checkpoint baseline rather than an unaided build. +function attemptContinued(attempt: InspectedAttempt): boolean { + if (attempt.dependency) { + return attempt.dependency.attempts.features.some(feature => + typeof feature.granted === 'number' && feature.granted > 0); + } + return (attempt.result?.levels ?? []).some(level => level.continued); +} + +function sheetLevels(attempt: InspectedAttempt | null): SheetLevel[] { + return (attempt?.result?.levels ?? []).map(level => ({ + level: level.level, + unaided: level.firstAbort ? null : level.firstScore, + score: level.finalScore, + repairs: level.used, + })); +} + +function sheetQuestlines(dependency: DependencyProgress): SheetQuestline[] { + const status = new Map(dependency.nodes.map(node => [node.id, node.status])); + const scored = new Map((dependency.score?.questlines ?? []) + .map(questline => [questline.id, questline.percentage ?? null])); + return (dependency.questlines ?? []).map(questline => ({ + id: questline.id, + title: questline.title, + score: scored.get(questline.id) ?? null, + nodes: questline.nodes.map(id => ({ id, status: status.get(id) ?? 'locked' })), + })); +} + +function sheetAttemptView(plan: CompiledCampaignPlan, state: CampaignAttemptState, + directory: string, interrupted: boolean): SheetAttemptView { + const inspected = inspectCampaignAttempt(plan, state, directory); + const execution = inspected.execution; + const logPath = execution + ? join(contained(directory, execution.output, 'campaign execution'), LOG_FILE) : null; + const log = logPath ? readTextTail(logPath) : ''; + const logUpdatedAt = logPath && existsSync(logPath) + ? new Date(statSync(logPath).mtimeMs).toISOString() : null; + const running = inspected.status === 'running' && !interrupted; + const pause = attemptPause(plan, state, directory); + const paused = running && pause?.resumedAt === null; + const repairLimit = repairBudgetLimit(plan.definition.repair, { + features: plan.featureCatalog?.definition.nodes.length ?? 1, + depths: plan.definition.levels.length, + }); + const progress = parseRunProgress(log, { repairs: repairLimit, + running, status: inspected.status, + dependency: plan.definition.mode?.id === 'dependency' }); + const metrics = attemptMetrics({ ...inspected, logUpdatedAt }); + const repairs = inspected.dependency ? dependencyRepairs(plan, inspected.dependency) : null; + return { + inspected, + attempt: { + id: inspected.id, + repetition: inspected.repetition, + status: interrupted && inspected.status === 'running' ? 'interrupted' : inspected.status, + phase: interrupted && inspected.status === 'running' + ? 'Controller stopped before completion' : paused ? `Paused at L${pause.depth}` : progress.phase, + stalling: attemptStalling({ ...inspected, paused }), + paused, + excluded: attemptExcluded(inspected), + continued: attemptContinued(inspected), + logUpdatedAt, + score: percentage(metrics?.final ?? null), + unaided: percentage(metrics?.first ?? null), + repairs: repairs ?? { used: metrics?.repairs ?? 0, budget: repairLimit }, + timeSec: metrics?.duration ?? null, + executionStartedAt: execution?.startedAt ?? null, + executionCompletedAt: execution?.completedAt ?? null, + executionCost: inspected.cost, + spend: inspected.spend, + spendPending: inspected.status === 'running' || inspected.status === 'pending', + completion: inspected.completion, + featureCompletion: inspected.dependency?.featureCompletion ?? null, + checkCategories: inspected.dependency?.checkCategories ?? null, + model: inspected.model, + effort: plan.attempts.find(entry => entry.id === inspected.id)?.effort, + variant: inspected.variantLabel, + climb: progress.series, + }, + }; +} + +const sheetCache = new Map(); + +// Facts and per-stack figures. No log text and no package walk: the climb and +// the phase come from the run output the controller already writes. +export function campaignSheet(resultsRoot: string, key: string, + { controllerActive = campaignLockIsActive }: ViewOptions = {}): CampaignSheet { + const directory = campaignDirectory(resultsRoot, key); + const reportPaths = ['report/report.html', 'report/export-manifest.json']; + const fingerprint = campaignFingerprint(directory, [CAMPAIGN_FILE.plan, CAMPAIGN_FILE.state, ...reportPaths], + [ARTIFACT_FILE.run, ARTIFACT_FILE.progressionState, 'depth-pause.json']); + const { plan, state } = dashboardCampaignState(directory); + const interrupted = controllerInterrupted(controllerActive, directory, plan, state.status); + const controllerOwner = readCampaignLock(directory)?.ownershipMarkerSha256 ?? null; + const cacheKey = `${directory}:${interrupted ? 'interrupted' : 'live'}:${controllerOwner ?? ''}`; + const cached = sheetCache.get(cacheKey); + if (cached?.fingerprint === fingerprint) return cached.sheet; + const views = state.attempts.map(attempt => + sheetAttemptView(plan, attempt, directory, interrupted)); + const comparison = compareCampaign({ + attempts: views.map(view => view.inspected) }); + const dependency = plan.definition.mode?.id === 'dependency'; + const stacks = plan.stacks.map(stack => { + const owned = views.filter(view => view.inspected.stack === stack.id); + const row = comparison.rows.find(entry => entry.stack === stack.id); + const eligible = row?.scopes.length === 1 ? row.runs.map(run => run.attempt) : []; + // Figures a repetition cannot average — the climb, the questline board, the + // per-level rows — come from the newest attempt that actually ran. + const latest = owned.findLast(view => view.inspected.execution !== null) ?? null; + const lead = latest?.inspected ?? null; + const metrics = lead ? attemptMetrics(lead) : null; + return { + stack: stack.id, + costPerValidRun: row?.costPerValidRun ?? null, + selectedAttemptId: latest?.attempt.id ?? null, + score: percentage(row?.final ?? null), + points: dependency ? uniquePoints(lead?.dependency ?? null) : metrics?.raw.final ?? null, + unaided: percentage(row?.first ?? null), + continued: owned.some(view => view.attempt.continued), + regressions: median(eligible.map(attemptRegressions)), + timeSec: row?.duration ?? null, + spend: executionSpend(owned.map(view => ({ cost: view.inspected.spend, knownCostUsd: view.inspected.spend.knownCostUsd }))), + spendPending: owned.some(view => view.attempt.spendPending), + completionRate: eligible.every(attempt => attempt.completion?.rate != null) + ? median(eligible.flatMap(attempt => attempt.completion?.rate == null + ? [] : [attempt.completion.rate])) : null, + n: row?.n ?? 0, + attempts: owned.map(view => view.attempt), + levels: dependency ? null : sheetLevels(lead), + questlines: lead?.dependency ? sheetQuestlines(lead.dependency) : null, + }; + }); + const sheet: CampaignSheet = { + key: basename(resolve(directory)), + id: plan.id, + title: plan.title, + status: interrupted ? 'attention-required' : state.status, + mode: plan.definition.mode?.id ?? 'sequential', + levels: plan.definition.levels, + repetitions: plan.definition.repetitions, + provisional: campaignFacts(plan).grading.status !== 'qualified', + mixedScope: comparison.mixedScope, + executions: state.summary.executions, + resumable: dependency && state.status === 'prepared' && state.summary.executions > 0, + controllerOwner: interrupted ? null : controllerOwner, + reportFiles: reportPaths.filter(path => existsSync(join(directory, path)) && statSync(join(directory, path)).isFile()), + createdAt: state.createdAt, + updatedAt: state.updatedAt, + facts: sheetFacts(plan), + stacks, + }; + sheetCache.set(cacheKey, { fingerprint, sheet }); + return sheet; +} + +function uniquePoints(dependency: DependencyProgress | null): { score: number; max: number } | null { + const unique = dependency?.score?.uniqueChecks; + if (!unique || unique.passedPoints == null || unique.availablePoints == null) return null; + return { score: unique.passedPoints, max: unique.availablePoints }; +} + +// Attempt sub-resources + +function attemptState(directory: string, attemptId: string): CampaignAttemptState { + const { state } = dashboardCampaignState(directory); + const attempt = state.attempts.find(item => item.plan.id === attemptId); + if (!attempt) throw new Error('campaign attempt does not exist'); + return attempt; +} + +export interface AttemptCheckGrade { + id: string; + level: number | null; + round: number | null; + score: { score: number; max: number } | null; + error?: string; +} + +export interface AttemptCheck { + category?: 'feature' | 'production' | 'interface' | null; + key: string; + id: string; + description: string; + points: number; + feature: string; + outcome: string; + regressed: boolean; + history: string[]; + observations: Array<{ status: string; summary: string | null; expected: string | null; actual: string | null } | null>; +} + +export interface AttemptChecks { + attemptId: string; + stack: string; + grades: AttemptCheckGrade[]; + checks: AttemptCheck[]; +} + +function checkOutcome(evidence: unknown): string { + const status = evidence !== null && typeof evidence === 'object' && 'status' in evidence + ? (evidence as { status?: unknown }).status : null; + if (status === 'passed') return 'pass'; + if (status === 'failed') return 'fail'; + return 'not-run'; +} + +function checkObservation(value: unknown): AttemptCheck['observations'][number] { + if (!value || typeof value !== 'object') return null; + const evidence = value as Partial; + if (!evidence.status || !CHECK_EVIDENCE_STATUSES.includes(evidence.status)) return null; + const status = evidenceDisposition(evidence.status).label; + if (evidence.sensitivity?.length) return { status, summary: 'Sensitive evidence omitted.', expected: null, actual: null }; + const text = (item: unknown): string | null => { + if (item == null) return null; + const result = redactCredentials(typeof item === 'string' ? item : JSON.stringify(item, null, 2)); + return result.length <= 12_000 ? result : `${result.slice(0, 12_000)}\n[Truncated. Full evidence is in Files.]`; + }; + return { status, summary: text(evidence.summary), expected: text(evidence.expected), actual: text(evidence.observation) }; +} + +function gradeDirectories(executionDirectory: string): AttemptCheckGrade[] { + if (!existsSync(executionDirectory)) return []; + const progression = join(executionDirectory, 'progression'); + if (existsSync(progression)) { + return readdirSync(progression, { withFileTypes: true }) + .filter(entry => entry.isDirectory() && PROGRESSION_ATTEMPT.test(entry.name)) + .map(entry => ({ id: `progression/${entry.name}`, + level: null, round: Number(PROGRESSION_ATTEMPT.exec(entry.name)?.[1] ?? 0), score: null })) + .sort((left, right) => (left.round ?? 0) - (right.round ?? 0)); + } + return readdirSync(executionDirectory, { withFileTypes: true }) + .filter(entry => entry.isDirectory() && GRADE_DIRECTORY.test(entry.name)) + .map(entry => { + const match = GRADE_DIRECTORY.exec(entry.name); + const level = match?.[1] ?? match?.[2] ?? null; + return { id: entry.name, level: level === null ? null : Number(level), + round: match?.[3] === undefined ? 0 : Number(match[3]), score: null }; + }) + .sort((left, right) => (left.level ?? 0) - (right.level ?? 0) + || (left.round ?? 0) - (right.round ?? 0)); +} + +// Per-check outcome and the history of every grade that reported it: the +// question "did this ever pass" has no other answer in the evidence. +export function attemptChecks(resultsRoot: string, key: string, attemptId: string): AttemptChecks { + const directory = campaignDirectory(resultsRoot, key); + const attempt = attemptState(directory, attemptId); + const execution = attempt.executions.at(-1) ?? null; + if (!execution) return { attemptId, stack: attempt.plan.stack, grades: [], checks: [] }; + const executionDirectory = contained(directory, execution.output, 'campaign execution'); + const grades = gradeDirectories(executionDirectory); + const { plan } = dashboardCampaignState(directory); + const metadata = new Map(plan.featureCatalog?.definition.nodes.flatMap(node => + node.gradingChecks.map(check => [check.id, check] as const)) ?? []); + const checks = new Map(); + grades.forEach((grade, index) => { + const path = join(executionDirectory, grade.id, ARTIFACT_FILE.gradeBundle); + if (!existsSync(path)) { + grade.error = 'grade bundle is missing'; + return; + } + let payload; + try { + payload = readArtifactPayload(path, { expectedKind: 'grade_bundle' }); + } catch (error) { + grade.error = redactCredentials(errorMessage(error)); + return; + } + grade.score = payload.totals?.score == null || payload.totals.max == null + ? null : { score: payload.totals.score, max: payload.totals.max }; + for (const suite of Object.values(payload.suites ?? {})) { + for (const feature of suite.features ?? []) { + for (const criterion of feature.criteria ?? []) { + const stableKey = criterion.stableKey ?? `${feature.name ?? ''}.${criterion.id ?? ''}`; + const entry = checks.get(stableKey) ?? { key: stableKey, id: criterion.id ?? stableKey, + description: criterionDescription(criterion), points: criterion.points ?? 0, + category: metadata.get(stableKey)?.category ?? null, + feature: feature.name ?? '', outcome: 'not-run', regressed: false, + history: grades.map(() => 'not-run'), observations: grades.map(() => null) }; + entry.history[index] = checkOutcome(criterion.evidence); + entry.observations[index] = checkObservation(criterion.evidence); + checks.set(stableKey, entry); + } + } + } + }); + for (const check of checks.values()) { + const conclusive = check.history.filter(outcome => outcome !== 'not-run'); + check.outcome = conclusive.at(-1) ?? 'not-run'; + check.regressed = conclusive.some((outcome, index) => + outcome === 'fail' && conclusive.slice(0, index).includes('pass')); + } + return { attemptId, stack: attempt.plan.stack, grades, checks: [...checks.values()] }; +} + +// The grade bundle names the criterion text `desc`. +function criterionDescription(criterion: object): string { + const record = criterion as { desc?: unknown; description?: unknown }; + if (typeof record.desc === 'string') return record.desc; + return typeof record.description === 'string' ? record.description : ''; +} + +export interface AttemptPackage { + attemptId: string; + stack: string; + executions: Array<{ + executionId: string; + ordinal: number; + status: string; + artifacts: DashboardArtifact[]; + visuals: DashboardArtifact[]; + truncated: boolean; + }>; +} + +export function attemptPackage(resultsRoot: string, key: string, + attemptId: string): AttemptPackage { + const directory = campaignDirectory(resultsRoot, key); + const attempt = attemptState(directory, attemptId); + return { + attemptId, + stack: attempt.plan.stack, + executions: attempt.executions.map(execution => { + const scanned = walkPublicExecutionArtifacts(directory, + contained(directory, execution.output, 'campaign execution')); + return { executionId: execution.id, ordinal: execution.ordinal, status: execution.status, + artifacts: scanned.artifacts, + visuals: scanned.artifacts.filter(artifact => artifact.kind === 'visual'), + truncated: scanned.truncated }; + }), + }; +} + +export interface AttemptLogSlice { + attemptId: string; + from: number; + offset: number; + size: number; + text: string; +} + +// Bytes after an offset, so a following view pays for growth rather than for +// the whole log on every poll. +export function attemptLogSlice(resultsRoot: string, key: string, attemptId: string, + fromOffset = 0): AttemptLogSlice { + const directory = campaignDirectory(resultsRoot, key); + const attempt = attemptState(directory, attemptId); + const execution = attempt.executions.at(-1) ?? null; + const path = execution + ? join(contained(directory, execution.output, 'campaign execution'), LOG_FILE) : null; + if (!path || !existsSync(path)) { + return { attemptId, from: fromOffset, offset: 0, size: 0, text: '' }; + } + const descriptor = openSync(path, 'r'); + try { + const size = fstatSync(descriptor).size; + // A rotated or truncated log invalidates the caller's offset. + const start = Math.min(Math.max(0, fromOffset), size); + const length = Math.min(size - start, MAX_LOG_BYTES); + const buffer = Buffer.alloc(length); + if (length) readSync(descriptor, buffer, 0, length, start); + return { attemptId, from: fromOffset, offset: start + length, size, + text: redactCredentials(buffer.toString('utf8')) }; + } finally { + closeSync(descriptor); + } +} + +// Campaign progression + +export interface ProgressionCatalogNode { + id: string; + title: string; + questline: string; + depth: number; + dependencies: string[]; +} + +export interface ProgressionStep { + sequence: number; + completedAt?: string | null; + completion?: number | null; + featureCompletion?: number | null; + action: 'build' | 'repair' | 'grant'; + targets: string[]; + // Node status after the event, index-aligned with `nodes`. + statuses: string[]; + score: number | null; + repairs: number; +} + +export interface ProgressionTrack { + liveCosts?: Array<{ completedAt: string; costUsd: number }>; + stack: string; + attemptId: string; + updatedAt: string; + steps: ProgressionStep[]; + costs?: Array<{ completedAt: string; cost: CostEvidence }>; +} + +export interface CampaignProgression { + key: string; + depths: number[]; + questlines: Array<{ id: string; title: string; nodes: string[] }>; + nodes: ProgressionCatalogNode[]; + stacks: ProgressionTrack[]; +} + +function progressionSnapshot(state: ProgressionState, nodeIds: readonly string[]): { + statuses: string[]; + score: number | null; + repairs: number; +} { + const average = progressionEngine.score(state).questlineAveragePercentage; + return { + statuses: nodeIds.map(id => state.nodes[id]?.status ?? 'locked'), + score: average == null ? null : Math.round(average * 10) / 10, + repairs: state.attempts.filter(attempt => attempt.repair !== undefined).length, + }; +} + +function progressionSteps(state: DependencyState, nodeIds: readonly string[], times: Map): ProgressionStep[] { + let replay = progressionEngine.initialize(state.definition); + return state.events.map(event => { + const action = progressionEngine.nextAction(replay); + if (event.type === 'repairs-granted') { + replay = progressionEngine.grantRepairs(replay, event.grant); + return { sequence: event.sequence, action: 'grant' as const, + targets: [...event.grant.nodeIds], ...progressionSnapshot(replay, nodeIds) }; + } + const targets = action.type === 'terminal' + ? [] : [...(action.prompt as DependencyPromptSelection).nodeIds]; + const repair = action.type === 'repair'; + replay = progressionEngine.recordResult(replay, event.result); + return { sequence: event.sequence, action: repair ? 'repair' as const : 'build' as const, + targets, ...progressionSnapshot(replay, nodeIds), + completedAt: event.result.evidence ? times.get(`${event.result.evidence.id}:${event.result.evidence.sha256}`) ?? null : null, + completion: scoreDependencyState(replay as DependencyState).completion.rate, + featureCompletion: dependencyCompletionBreakdown(replay as DependencyState).featureCompletion.rate }; + }); +} + +const progressionCache = new Map(); + +// The catalog subgraph the campaign runs, plus one node-status snapshot per +// progression event: the graph and its replay come from the same read. +export function campaignProgression(resultsRoot: string, key: string): CampaignProgression | null { + const directory = campaignDirectory(resultsRoot, key); + const { plan, state } = dashboardCampaignState(directory); + if (plan.definition.mode?.id !== 'dependency' || !plan.featureCatalog + || !plan.dependencyPolicy) return null; + const fingerprint = campaignFingerprint(directory, [CAMPAIGN_FILE.plan, CAMPAIGN_FILE.state], + [ARTIFACT_FILE.progressionState, ARTIFACT_FILE.run]); + const cached = progressionCache.get(directory); + if (cached?.fingerprint === fingerprint) return cached.view; + const progression = compileProgressionInput(dependencyRuntimeDefinition( + plan.featureCatalog, plan.dependencyPolicy)); + const definition = progression.definition; + const nodeIds = definition.nodes.map(node => node.id); + const owned = new Set(nodeIds); + const stacks: ProgressionTrack[] = []; + for (const attempt of state.attempts) { + const execution = attempt.executions.at(-1) ?? null; + if (!execution) continue; + const path = join(contained(directory, execution.output, 'campaign execution'), + ARTIFACT_FILE.progressionState); + if (!existsSync(path)) continue; + const stored = readProgressionState(path, { + progression, + featureCatalogIdentity: plan.featureCatalog.identity, + dependencyPolicyIdentity: plan.dependencyPolicy.identity, + owner: campaignProgressionOwner(plan, attempt.plan, { workspace: true }), + }); + const executionDirectory = contained(directory, execution.output, 'campaign execution'); + const times = new Map(); + for (const grade of gradeDirectories(executionDirectory)) { + const bundlePath = join(executionDirectory, grade.id, ARTIFACT_FILE.gradeBundle); + if (!existsSync(bundlePath)) continue; + try { + const bundle = readArtifact(bundlePath, { expectedKind: 'grade_bundle' }); + times.set(`${bundle.id}:${sha256(canonicalDefinitionJson(bundle))}`, bundle.timestamps.completedAt); + } catch { /* Missing or invalid evidence must not invent a chart timestamp. */ } + } + const costs: NonNullable = []; + try { + const run = readArtifact(join(executionDirectory, ARTIFACT_FILE.run), { expectedKind: 'benchmark_run' }); + if (run.attempt.parentId !== attempt.plan.id) throw new Error('Run belongs to another attempt'); + const checkpoints = (run.payload as { checkpoints?: RunCheckpoint[] }).checkpoints ?? []; + for (const checkpoint of checkpoints) { + try { + const evidencePath = contained(executionDirectory, checkpoint.evidence.path, 'cost checkpoint'); + if (sha256(readFileSync(evidencePath)) !== checkpoint.evidence.sha256) continue; + const grade = readArtifact(evidencePath, { expectedKind: 'grade_bundle' }); + if (grade.timestamps.completedAt && checkpoint.executionCost.status !== 'unknown') { + costs.push({ completedAt: grade.timestamps.completedAt, cost: checkpoint.executionCost }); + } + } catch { /* Missing evidence does not establish a timed cost. */ } + } + } catch { /* A run may not have saved its first checkpoint yet. */ } + stacks.push({ stack: attempt.plan.stack, attemptId: attempt.plan.id, + updatedAt: new Date(statSync(path).mtimeMs).toISOString(), costs, + steps: progressionSteps(stored.state as DependencyState, nodeIds, times) }); + } + const view: CampaignProgression = { + key: basename(resolve(directory)), + depths: [...new Set(definition.nodes.map(node => node.level))].sort((a, b) => a - b), + questlines: definition.questlines.map(questline => ({ id: questline.id, + title: questline.title, nodes: [...questline.nodes] })), + nodes: definition.nodes.map(node => ({ id: node.id, title: node.title, + questline: node.questline, depth: node.level, + dependencies: node.dependencies.filter(id => owned.has(id)) })), + stacks, + }; + progressionCache.set(directory, { fingerprint, view }); + return view; +} + +type LiveCosts = Map>>; +const liveCampaignCache = new Map(); + +function campaignLiveCosts(resultsRoot: string, key: string) { + const directory = campaignDirectory(resultsRoot, key); + const cached = liveCampaignCache.get(directory); + if (cached && (cached.pending || Date.now() - cached.at < 5000)) return cached.value; + const { state } = dashboardCampaignState(directory); + const entry = { at: Date.now(), pending: true, value: cached?.value ?? new Map() as LiveCosts }; + const refresh = async () => { + const costs = new Map>>(); + await Promise.all(state.attempts.map(async attempt => { + const execution = attempt.executions.at(-1); + // Restored executions can carry older transcript history. Keep their saved + // receipts until response identities are available across that boundary. + if (attempt.status !== 'running' || attempt.executions.length !== 1 || !execution?.startedAt + || !['claude-code', 'codex'].includes(attempt.plan.agentAdapter)) return; + try { + costs.set(attempt.plan.id, await liveTranscriptCost(contained(directory, execution.output, 'campaign execution'), + attempt.plan.agentAdapter, attempt.plan.pricing.rates, attempt.plan.model, execution.startedAt)); + } catch { /* Missing, conflicting, or unpriced usage leaves saved receipts visible. */ } + })); + entry.value = costs; + }; + if (liveCampaignCache.size >= 32) liveCampaignCache.delete(liveCampaignCache.keys().next().value!); + liveCampaignCache.set(directory, entry); + void refresh().catch(() => { entry.value = new Map(); }).finally(() => { + entry.pending = false; + entry.at = Date.now(); + }); + return entry.value; +} + +export function campaignLiveSheet(resultsRoot: string, key: string, options: ViewOptions = {}): CampaignSheet { + const sheet = structuredClone(campaignSheet(resultsRoot, key, options)); + const live = campaignLiveCosts(resultsRoot, key); + const directory = campaignDirectory(resultsRoot, key); + const { state } = dashboardCampaignState(directory); + for (const stack of sheet.stacks) { + for (const attempt of stack.attempts) { + const execution = state.attempts.find(entry => entry.plan.id === attempt.id)?.executions.at(-1); + if (execution) { + const path = join(contained(directory, execution.output, 'campaign execution'), LOG_FILE); + if (existsSync(path)) { + const updatedAt = new Date(statSync(path).mtimeMs).toISOString(); + if (attempt.logUpdatedAt !== updatedAt) { + attempt.logUpdatedAt = updatedAt; + const progress = parseRunProgress(readTextTail(path), { repairs: attempt.repairs.budget, + running: attempt.status === 'running', status: attempt.status, dependency: sheet.mode === 'dependency' }); + if (attempt.status === 'running' && !attempt.paused) attempt.phase = progress.phase; + attempt.climb = progress.series; + } + } + } + if (attempt.status !== 'running') continue; + const snapshot = live.get(attempt.id); + if (snapshot?.activityUpdatedAt) { + attempt.activityUpdatedAt = snapshot.activityUpdatedAt; + attempt.stalling = attemptStalling(attempt); + } + const total = snapshot?.costs.at(-1)?.costUsd; + attempt.liveSpend = liveCostTotal(attempt.status, total, attempt.spend.costUsd); + } + if (stack.attempts.some(attempt => attempt.liveSpend !== undefined) + && stack.attempts.every(attempt => attempt.liveSpend !== undefined || attempt.spend.status === 'exact')) { + stack.liveSpend = stack.attempts.reduce((sum, attempt) => sum + (attempt.liveSpend ?? attempt.spend.costUsd!), 0); + } + } + return sheet; +} + +// Transcript and log updates do not need another graph replay or evidence payload. +export function campaignLiveUpdate(resultsRoot: string, key: string, options: ViewOptions = {}) { + const sheet = campaignLiveSheet(resultsRoot, key, options); + const live = campaignLiveCosts(resultsRoot, key); + return { updatedAt: sheet.updatedAt, status: sheet.status, stacks: sheet.stacks.map(stack => ({ + stack: stack.stack, liveSpend: stack.liveSpend ?? null, + attempts: stack.attempts.filter(attempt => attempt.executionStartedAt !== null).map(attempt => ({ + id: attempt.id, phase: attempt.phase, logUpdatedAt: attempt.logUpdatedAt, + activityUpdatedAt: attempt.activityUpdatedAt ?? null, stalling: attempt.stalling, + climb: attempt.climb, liveSpend: attempt.liveSpend ?? null, + liveCosts: attempt.liveSpend === undefined ? [] : live.get(attempt.id)?.costs ?? [], + })), + })) }; +} +export type CampaignLiveUpdate = ReturnType; + +export function campaignLiveProgression(resultsRoot: string, key: string): CampaignProgression | null { + const progression = structuredClone(campaignProgression(resultsRoot, key)); + if (!progression) return null; + const live = campaignLiveCosts(resultsRoot, key); + const sheet = campaignSheet(resultsRoot, key); + const running = new Set(sheet.stacks.flatMap(stack => + stack.attempts.filter(attempt => attempt.status === 'running').map(attempt => attempt.id))); + for (const stack of sheet.stacks) for (const attempt of stack.attempts) { + const snapshot = live.get(attempt.id); + if (running.has(attempt.id) && snapshot?.costs.length + && !progression.stacks.some(track => track.attemptId === attempt.id)) { + progression.stacks.push({ stack: stack.stack, attemptId: attempt.id, + updatedAt: snapshot.activityUpdatedAt ?? sheet.updatedAt, steps: [], costs: [] }); + } + } + for (const track of progression.stacks) { + if (!running.has(track.attemptId)) continue; + const snapshot = live.get(track.attemptId); + if (snapshot?.costs.length && liveCostTotal('running', snapshot.costs.at(-1)!.costUsd, + track.costs?.at(-1)?.cost.costUsd ?? null) !== undefined) { + track.liveCosts = snapshot.costs; + } + } + return progression; +} + +export function attemptTranscript(resultsRoot: string, key: string, attemptId: string, + session: string, before?: number) { + const directory = campaignDirectory(resultsRoot, key); + const attempt = attemptState(directory, attemptId); + return readAttemptTranscript(attempt.executions.map((execution, index) => ({ + directory: contained(directory, execution.output, 'campaign execution'), + label: `Execution ${index + 1}`, + })), attempt.plan.agentAdapter, session, before); +} diff --git a/tools/stack-bench/dashboard/public/app.ts b/tools/stack-bench/dashboard/public/app.ts new file mode 100644 index 00000000000..55b75b20333 --- /dev/null +++ b/tools/stack-bench/dashboard/public/app.ts @@ -0,0 +1,755 @@ +/// +/// +import type { readExecutionJob } from '../../src/campaigns/execution-jobs.js'; +import type { RunSetupCatalog, RunSetupRequest, RunSetupReview } from '../../src/campaigns/run-setup.js'; +import { initialRun, readRunForm, runSetupPage } from './views/run-setup.js'; +import type { TranscriptPage } from '../dashboard-transcript.js'; + + +// The client: real paths, one event stream, and keyed reconciliation so a +// refresh does not move what the pointer is on. Every view is a pure function +// of data; the only DOM work in the dashboard happens here. + +import type { AttemptChecks, AttemptPackage, CampaignLiveUpdate, CampaignProgression, CampaignSheet, OverviewEntry } + from '../dashboard-views.js'; +import type { DashboardPlan } from '../dashboard-model.js'; +import type { readCampaignTimeBudget } from '../../src/campaigns/campaign-time-grant.js'; +import { type QuestlineView, campaignPage, replayTimeline, selectedProgression } from './views/campaign.js'; +import { type AttemptTab, attemptPage } from './views/attempt.js'; +import { type CampaignFilter, campaignsPage } from './views/campaigns.js'; +import { type Page, type RunForm, plansPage, topbar } + from './views/plans.js'; +import { duration, elapsed, esc } from './format.js'; + +const FALLBACK_MS = 15_000; +const TABS: readonly AttemptTab[] = ['checks', 'transcript', 'screenshots', 'files', 'log']; +const VIEWS: readonly QuestlineView[] = ['grid', 'graph', 'replay']; +const FILTERS: readonly CampaignFilter[] = ['all', 'attention', 'completed', 'ready']; + +interface Route { + key: string; + attempt: string; + plans: boolean; + newRun: boolean; + filter: CampaignFilter; + view: QuestlineView; + chart: 'completion' | 'cost' | 'distribution'; + unit: 'checks' | 'features'; + step: number; + tab: AttemptTab; +} + +const state = { + overview: [] as OverviewEntry[], + plans: [] as DashboardPlan[], + overviewLoaded: false, + plansLoaded: false, + pendingJobs: new Map; dispatchError: string | null }>(), + setup: null as RunSetupCatalog | null, + setupRequest: null as RunSetupRequest | null, + setupReview: null as RunSetupReview | null, + canStart: false, + csrfToken: '', + readError: '', + form: { error: '' } as RunForm, + sheets: new Map(), + progression: new Map(), + hiddenChartRuns: new Map>(), + checks: new Map(), + evidence: new Map(), + timeBudgets: new Map>(), + timeGrantIds: new Map(), + timeGrantMinutes: '120', + transcript: { attempt: '', session: '', before: undefined as number | undefined, page: null as TranscriptPage | null }, + log: { attempt: '', text: '', offset: 0 }, +}; +let fallback = 0; +let events: EventSource | null = null; +let playing = 0; +let submitting = false; +let loading = false; +let loadVersion = 0; +let loadTask: Promise | null = null; +let loadController = new AbortController(); +let refreshPending = false; +let pendingNavigation = false; +let pendingKeys: Set | null = new Set(); +let pendingOverview = false; + +function route(): Route { + const url = new URL(location.href); + const parts = url.pathname.split('/').filter(Boolean); + const pick = (values: readonly Value[], name: string, fall: Value): Value => + values.find(value => value === url.searchParams.get(name)) ?? fall; + return { + key: parts[0] === 'c' ? parts[1] ?? '' : '', + attempt: parts[2] === 'a' ? parts[3] ?? '' : '', + plans: parts[0] === 'plans' || parts[0] === 'new', + newRun: parts[0] === 'new', + filter: pick(FILTERS, 'filter', 'all'), + view: pick(VIEWS, 'questlines', 'grid'), + chart: pick(['completion', 'cost', 'distribution'] as const, 'chart', 'completion'), + unit: pick(['checks', 'features'] as const, 'unit', 'features'), + step: Math.max(0, Number(url.searchParams.get('step') ?? 0)), + tab: pick(TABS, 'tab', 'checks'), + }; +} + +async function read(url: string): Promise { + const version = loadVersion; + try { + const response = await fetch(url, { headers: { accept: 'application/json' }, + signal: AbortSignal.any([loadController.signal, AbortSignal.timeout(30_000)]) }); + if (!response.ok) { + const failure = await response.json().catch(() => ({})) as { error?: string }; + if (version === loadVersion) state.readError = failure.error ?? `Request failed (${response.status}).`; + return null; + } + const payload = await response.json() as Payload; + return version === loadVersion ? payload : null; + } catch { + if (version === loadVersion) state.readError = 'The dashboard did not respond. Check its connection and try again.'; + return null; + } +} + +function attemptUrl(current: Route, suffix: string): string { + return `/api/campaigns/${encodeURIComponent(current.key)}` + + `/attempts/${encodeURIComponent(current.attempt)}/${suffix}`; +} + +async function readLog(current: Route): Promise { + const version = loadVersion; + if (state.log.attempt !== current.attempt) state.log = { attempt: current.attempt, text: '', offset: 0 }; + try { + const response = await fetch(attemptUrl(current, `log?from=${state.log.offset}`), + { signal: AbortSignal.any([loadController.signal, AbortSignal.timeout(30_000)]) }); + if (!response.ok) throw new Error('Log request failed'); + const text = await response.text(); + if (version !== loadVersion || state.log.attempt !== current.attempt) return; + state.log.text += text; + state.log.offset = Number(response.headers.get('x-stack-bench-log-offset') ?? state.log.offset); + } catch { + if (version === loadVersion) state.readError = 'Could not load the run log. Try again.'; + } +} + +function chrome(current: Route): string { + const sheet = state.sheets.get(current.key) ?? null; + const page: Page = current.plans ? 'plans' + : current.key && !current.attempt ? 'campaign' : 'campaigns'; + return topbar({ page, key: current.key, canStart: state.canStart, error: state.form.error, + reportFiles: sheet?.reportFiles, + controllerOwner: page === 'campaign' ? sheet?.controllerOwner : null, + resumable: state.canStart && page === 'campaign' && (sheet?.resumable ?? false) }); +} + +function page(current: Route): string { + const sheet = state.sheets.get(current.key) ?? null; + const pending = state.pendingJobs.get(current.key); + if (pending) return `

${esc(pending.pendingJob.job.key)}

${esc(pending.pendingJob.status)}

` + + `

${esc(pending.dispatchError ?? pending.pendingJob.error ?? pending.pendingJob.capacityWait?.reason ?? 'Waiting for the campaign to start. This page updates automatically.')}

` + + (state.canStart && ['queued', 'running'].includes(pending.pendingJob.status) + ? '
' : '') + + (state.canStart && pending.pendingJob.status === 'queued' && pending.dispatchError + ? '
' : '') + + (state.form.error ? `

${esc(state.form.error)}

` : '') + '
'; + if (current.newRun) return runSetupPage(state.setup, state.setupRequest, state.setupReview, state.form.error, state.canStart); + if (current.plans) { + return plansPage({ plans: state.plans, + loading: loading && !state.plansLoaded }); + } + if (!current.key) { + const running = state.overview.filter(campaign => campaign.status === 'running') + .map(campaign => state.sheets.get(campaign.key)) + .filter((entry): entry is CampaignSheet => entry !== undefined); + return campaignsPage({ campaigns: state.overview, sheets: running, filter: current.filter, + loading: loading && !state.overviewLoaded }); + } + if (!sheet) return `
Campaigns / ` + + `${esc(current.key)}
`; + if (current.attempt) { + return attemptPage({ sheet, progression: state.progression.get(current.key) ?? null, + attemptId: current.attempt, tab: current.tab, + timeBudget: state.timeBudgets.get(current.attempt), canControl: state.canStart, + controlError: state.form.error, + transcript: state.transcript.attempt === current.attempt ? state.transcript.page : null, + checks: state.checks.get(current.attempt) ?? null, + evidence: state.evidence.get(current.attempt) ?? null, + log: state.log.attempt === current.attempt ? state.log.text : '' }); + } + return campaignPage({ sheet, progression: state.progression.get(current.key) ?? null, + view: current.view, step: current.step, chart: current.chart, unit: current.unit, + hiddenChartRuns: state.hiddenChartRuns.get(current.key) }); +} + +function sync(current: Element, next: Element): void { + for (const name of [...current.getAttributeNames()]) { + if (current.tagName === 'DETAILS' && name === 'open') continue; + if (!next.hasAttribute(name)) current.removeAttribute(name); + } + for (const name of next.getAttributeNames()) { + if (current.getAttribute(name) !== next.getAttribute(name)) { + current.setAttribute(name, next.getAttribute(name) ?? ''); + } + } +} + +// Replace only what changed, matching children by position and data-key, so a +// row under the pointer keeps its hover across a refetch. +function patch(current: Element, next: Element): void { + const mine = [...current.children]; + const theirs = [...next.children]; + if (mine.length !== theirs.length || current.childNodes.length !== mine.length + || next.childNodes.length !== theirs.length) { + current.replaceChildren(...next.childNodes); + return; + } + mine.forEach((child, index) => { + const other = theirs[index]!; + if (child.tagName !== other.tagName + || child.getAttribute('data-key') !== other.getAttribute('data-key')) { + child.replaceWith(other); + return; + } + if (child.outerHTML === other.outerHTML) return; + if (!child.children.length || !other.children.length) { + child.replaceWith(other); + return; + } + // Moving option nodes can change a native select's value during reconciliation. + const selected = other instanceof HTMLSelectElement ? other.value : null; + sync(child, other); + patch(child, other); + if (child instanceof HTMLSelectElement && selected !== null) child.value = selected; + }); +} + +function updateTimeTotal(field: HTMLInputElement): void { + const total = field.form?.querySelector('[data-time-base]'); + if (total) total.textContent = field.validity.valid + ? `Limit after request: ${duration((Number(total.dataset.timeBase) + field.valueAsNumber) * 60)}` + : 'Enter positive whole minutes.'; +} + +function render(): void { + const current = route(); + const root = document.body; + const next = document.createElement('body'); + const ready = current.plans ? state.plansLoaded : current.key + ? state.sheets.has(current.key) : state.overviewLoaded; + next.innerHTML = `${chrome(current)}
` + + (state.readError ? `` : '') + + (loading && !ready && current.key ? `

${current.attempt ? 'Run details' : 'Campaign'}

` + + '
Loading…
' : page(current)) + + '
'; + const transcript = root.querySelector('.transcript'); + const scroll = transcript?.scrollTop ?? 0; + const follow = !transcript || transcript.scrollHeight - scroll - transcript.clientHeight < 40; + const openTools = [...root.querySelectorAll('.transcript details[open]')].map(el => el.dataset.key); + patch(root, next); + const updated = root.querySelector('.transcript'); + if (updated) { + for (const tool of updated.querySelectorAll('details')) tool.open = openTools.includes(tool.dataset.key); + updated.scrollTop = follow ? updated.scrollHeight : scroll; + } + // Keep the time limit input across background refreshes. + for (const field of document.querySelectorAll('form[data-run] input')) { + if (field.name === 'minutes') { + field.value = state.timeGrantMinutes; + updateTimeTotal(field); + } + } + for (const form of document.querySelectorAll('form[data-run]')) { + form.setAttribute('aria-busy', String(submitting)); + if (submitting && form.dataset.run?.startsWith('setup-')) { + const submit = form.querySelector('button[type=submit]'); + if (submit) submit.textContent = form.dataset.run === 'setup-review' ? 'Preparing review…' : 'Starting…'; + } + for (const button of form.querySelectorAll('button[type=submit]')) { + button.disabled = submitting || (!state.canStart && form.dataset.run?.startsWith('setup-')) || (form.dataset.run === 'grant-time' + && (state.timeBudgets.get(current.attempt)?.grants.some(grant => grant.disposition === 'pending') ?? false)); + } + } +} + +function load(navigation = false, changedKey?: string, liveOnly = false): Promise { + refreshPending = true; + pendingNavigation ||= navigation; + pendingOverview ||= !liveOnly; + if (changedKey) pendingKeys?.add(changedKey); + else pendingKeys = null; + if (navigation) { + state.form = { error: '' }; + ++loadVersion; + loadController.abort(); + } + if (loadTask) return loadTask; + if (document.hidden && !navigation) return Promise.resolve(); + loadTask = (async () => { + while (refreshPending && (!document.hidden || pendingNavigation)) { + const showLoading = pendingNavigation; + const keys = pendingKeys; + const refreshOverview = pendingOverview; + refreshPending = pendingNavigation = false; + pendingOverview = false; + pendingKeys = new Set(); + const version = ++loadVersion; + loadController = new AbortController(); + loading = true; + state.readError = ''; + if (showLoading) render(); + try { + await loadData(version, keys, refreshOverview); + } catch { + if (version === loadVersion) state.readError = 'Could not load this page. Try again.'; + } finally { + if (version === loadVersion) { + loading = false; + render(); + } + } + } + })().finally(() => { loadTask = null; }); + return loadTask; +} + +async function loadData(version: number, changedKeys: Set | null, refreshOverview: boolean): Promise { + const current = route(); + if (!refreshOverview) { + const keys = current.key ? [current.key] : [...state.sheets.keys()] + .filter(key => state.sheets.get(key)?.status === 'running' && (!changedKeys || changedKeys.has(key))); + await Promise.all(keys.map(async key => { + const sheet = state.sheets.get(key); + if (!sheet) return; + const update = await read(`/api/campaigns/${encodeURIComponent(key)}/live`); + if (!update || version !== loadVersion) return; + if (update.updatedAt !== sheet.updatedAt || update.status !== sheet.status) { + void load(false, key); // Evidence changed while a log refresh was in flight. + return; + } + const progression = state.progression.get(key); + for (const stack of sheet.stacks) { + const fresh = update.stacks.find(entry => entry.stack === stack.stack); + stack.liveSpend = fresh?.liveSpend ?? undefined; + for (const attempt of stack.attempts) { + const live = fresh?.attempts.find(entry => entry.id === attempt.id); + if (!live) continue; + const { liveCosts, liveSpend, ...fields } = live; + Object.assign(attempt, fields, { liveSpend: liveSpend ?? undefined }); + let track = progression?.stacks.find(entry => entry.attemptId === attempt.id); + if (!track && progression && liveCosts.length) { + track = { stack: stack.stack, attemptId: attempt.id, updatedAt: update.updatedAt, steps: [], costs: [] }; + progression.stacks.push(track); + } + if (track) track.liveCosts = liveCosts.length ? liveCosts : undefined; + } + } + })); + if (version !== loadVersion) return; + if (current.tab === 'transcript') await readTranscript(); + else if (current.attempt && current.tab === 'log') await readLog(current); + return; + } + const setupRequest = current.newRun && !state.setupRequest ? read('/api/run-setup').then(catalog => { + if (catalog && version === loadVersion) { + state.setup = catalog; state.setupRequest ??= initialRun(catalog); state.plansLoaded = true; render(); + } + }) : null; + const plansRequest = current.plans && !current.newRun ? read('/api/plans').then(plans => { + if (plans && version === loadVersion) { + state.plans = plans; + state.plansLoaded = true; + render(); + } + }) : null; + if (!state.csrfToken && (current.key || current.plans)) { + const session = await read<{ canStart: boolean; csrfToken: string }>('/api/session'); + if (version !== loadVersion) return; + if (session) Object.assign(state, session); + } + if (!current.key && !current.plans && (refreshOverview || !state.csrfToken)) { + const overview = await read<{ campaigns: OverviewEntry[]; canStart: boolean; + csrfToken: string; }>('/api/overview'); + if (version !== loadVersion) return; + if (overview) Object.assign(state, { overview: overview.campaigns, overviewLoaded: true, + canStart: overview.canStart, csrfToken: overview.csrfToken }); + render(); + } + if (current.plans) { + await Promise.all([plansRequest, setupRequest]); + if (version !== loadVersion) return; + render(); + return; + } + if (!current.key) { + const campaigns = state.overview.filter(entry => entry.status === 'running' + && (!changedKeys || changedKeys.has(entry.key) || !state.sheets.has(entry.key))); + await Promise.all(campaigns.map(async campaign => { + const sheet = await read(`/api/campaigns/${encodeURIComponent(campaign.key)}`); + if (version !== loadVersion) return; + if (sheet) state.sheets.set(campaign.key, sheet); + render(); + })); + return; + } + const result = await read; dispatchError: string | null }>(`/api/campaigns/${encodeURIComponent(current.key)}`); + if (version !== loadVersion) return; + if (result && 'pendingJob' in result) { state.pendingJobs.set(current.key, result); render(); return; } + state.pendingJobs.delete(current.key); + const sheet = result; + if (sheet) state.sheets.set(current.key, sheet); + render(); + if (sheet?.mode === 'dependency') { + const progression = await read( + `/api/campaigns/${encodeURIComponent(current.key)}/progression`); + if (version !== loadVersion) return; + if (progression) state.progression.set(current.key, progression); + render(); + } + if (!current.attempt) return; + const timeBudget = await read>(attemptUrl(current, 'time')); + if (version !== loadVersion) return; + if (timeBudget) { + state.timeBudgets.set(current.attempt, timeBudget); + if (timeBudget.grants.some(grant => grant.request.grantId === state.timeGrantIds.get(current.attempt) + && grant.disposition !== 'pending')) state.timeGrantIds.delete(current.attempt); + } + if (current.tab === 'checks') { + const checks = await read(attemptUrl(current, 'checks')); + if (checks) state.checks.set(current.attempt, checks); + } else if (current.tab === 'screenshots' || current.tab === 'files') { + const evidence = await read(attemptUrl(current, 'package')); + if (evidence) state.evidence.set(current.attempt, evidence); + } else if (current.tab === 'transcript') { + await readTranscript(); + } else if (current.tab === 'log') { + await readLog(current); + } + render(); +} + +function go(href: string): void { + history.pushState(null, '', href); + void load(true); +} + +function stepTo(offset: number): void { + const current = route(); + const progression = state.progression.get(current.key) ?? null; + const sheet = state.sheets.get(current.key); + if (!progression || !sheet) return; + const total = replayTimeline(selectedProgression(progression, sheet)).length; + const next = Math.min(Math.max(0, current.step + offset), Math.max(0, total - 1)); + const url = new URL(location.href); + url.searchParams.set('step', String(next)); + history.replaceState(null, '', `${url.pathname}${url.search}`); + render(); +} + +function subscribe(): void { + if (document.hidden || events) return; + const source = events = new EventSource('/api/events'); + const changed = (event: MessageEvent): void => { + const current = route(); + const message = JSON.parse(event.data) as { key?: string; attemptId?: string }; + const ids = message.attemptId ? [message.attemptId] + : state.sheets.get(message.key ?? '')?.stacks.flatMap(stack => stack.attempts.map(attempt => attempt.id)) ?? []; + for (const id of ids) { + // Keep the visible tab stable until its replacement data arrives. + if (message.key === current.key && id === current.attempt) continue; + state.checks.delete(id); + state.evidence.delete(id); + } + if (current.plans || (current.key && message.key !== current.key)) return; + if (current.attempt && message.attemptId && message.attemptId !== current.attempt) return; + void load(false, message.key); + }; + source.addEventListener('campaign', changed); + source.addEventListener('log', event => { + const current = route(); + const message = JSON.parse((event as MessageEvent).data) as { key: string }; + if (!current.plans && (!current.key || message.key === current.key)) void load(false, message.key, true); + }); + source.addEventListener('open', () => { + if (fallback) clearInterval(fallback); + fallback = 0; + void load(); + }); + // Recover missed campaign changes while the stream is down. + source.addEventListener('error', () => { + fallback ||= window.setInterval(() => void load(), FALLBACK_MS); + }); +} + +let helpClose = 0; +for (const type of ['pointerover', 'pointerout', 'focusin', 'focusout']) document.addEventListener(type, event => { + if (!(event.target instanceof Element)) return; + const series = event.target.closest('[data-chart-series]'); + if (!series) return; + const lines = [...series.closest('.page')?.querySelectorAll('[data-chart-series]') ?? []]; + const active = (type === 'pointerover' || type === 'focusin') + && lines.some(line => line.dataset.chartSeries === series.dataset.chartSeries); + for (const line of lines) { + line.classList.toggle('is-muted', active && line.dataset.chartSeries !== series.dataset.chartSeries); + line.classList.toggle('is-highlighted', active && line.dataset.chartSeries === series.dataset.chartSeries); + } +}); +for (const type of ['pointerover', 'focusin']) document.addEventListener(type, event => { + if (!(event.target instanceof Element)) return; + if (!event.target.closest('.metric-help, .metric-tooltip')) return; + clearTimeout(helpClose); + const trigger = event.target.closest('.metric-help'); + trigger?.click(); +}); +for (const type of ['pointerout', 'focusout']) document.addEventListener(type, event => { + if (!(event.target instanceof Element) + || !event.target.closest('.metric-help, .metric-tooltip')) return; + clearTimeout(helpClose); + helpClose = window.setTimeout(() => { + if (document.querySelector('.metric-help:hover, .metric-help:focus, .metric-tooltip:hover')) return; + document.querySelector('.metric-tooltip:popover-open')?.hidePopover(); + }, 150); +}); + +document.addEventListener('click', event => { + if (event.defaultPrevented || event.button !== 0 || event.metaKey || event.ctrlKey + || event.shiftKey || event.altKey) return; + const chartToggle = (event.target as Element | null)?.closest('[data-chart-run], [data-chart-stack]'); + if (chartToggle) { + const key = route().key; + const hidden = state.hiddenChartRuns.get(key) ?? new Set(); + const ids = chartToggle.dataset.chartRun !== undefined ? [chartToggle.dataset.chartRun] + : state.sheets.get(key)?.stacks.find(stack => stack.stack === chartToggle.dataset.chartStack) + ?.attempts.map(attempt => attempt.id) ?? []; + const hide = ids.some(id => !hidden.has(id)); + for (const id of ids) { if (hide) hidden.add(id); else hidden.delete(id); } + state.hiddenChartRuns.set(key, hidden); + render(); + return; + } + if ((event.target as Element | null)?.closest('[data-retry]')) { + void load(true); + return; + } + const shot = (event.target as Element | null)?.closest('[data-shot]'); + if (shot) { + const dialog = document.querySelector('.lightbox'); + const image = dialog?.querySelector('img'); + if (!dialog || !image) return; + image.src = shot.dataset.shot ?? ''; + image.alt = shot.dataset.shotName ?? ''; + dialog.showModal(); + return; + } + if (event.target instanceof HTMLDialogElement) event.target.close(); + const link = (event.target as Element | null)?.closest('a'); + const href = link?.getAttribute('href') ?? ''; + if (!href || href.startsWith('/api/') || !/^[/?]/.test(href)) return; + event.preventDefault(); + go(href.startsWith('?') ? `${location.pathname}${href}` : href); +}); + +// Controls require the browser token and same origin; the server re-reads the plan. +async function post(form: HTMLFormElement): Promise { + if (submitting) return; + const current = route(); + const data = new FormData(form); + const action = form.dataset.run; + // A response belongs to this form, even if the user leaves before it arrives. + const submittedForm = state.form = { error: '' }; + if (action === 'setup-review' || action === 'setup-start') { + if (action === 'setup-review') state.setupRequest = readRunForm(form, state.setup!); + submitting = true; render(); + try { + const response = await fetch(action === 'setup-review' ? '/api/runs/prepare' : '/api/runs', { + method: 'POST', headers: { 'content-type': 'application/json', 'x-stack-bench-token': state.csrfToken }, + body: JSON.stringify(action === 'setup-review' ? state.setupRequest + : { request: state.setupReview!.request, reviewId: state.setupReview!.reviewId }), + }); + const result = await response.json(); + if (state.form !== submittedForm) return; + if (!response.ok) { + submittedForm.error = result.error ?? `Request failed (${response.status})`; + if (response.status === 403) { state.csrfToken = ''; void load(); } + return; + } + if (action === 'setup-review') state.setupReview = result as RunSetupReview; + else { + state.setupReview = null; state.setupRequest = null; + go(`/c/${encodeURIComponent(result.campaignKey)}`); + } + } catch { submittedForm.error = 'Could not confirm the request. Retry with the same setup; it cannot create a second job.'; } + finally { submitting = false; render(); } + return; + } + + const resumeWithTime = action === 'grant-time' && form.dataset.resume === 'true'; + const existing = action === 'job-start' || action === 'job-cancel' || action === 'resume' || action === 'stop' || action === 'grant-time'; + if (!existing) return; + // Retain the ID after an uncertain response, so retry cannot add time twice. + if (action === 'grant-time' && !state.timeGrantIds.has(current.attempt)) { + state.timeGrantIds.set(current.attempt, crypto.randomUUID()); + } + const grantId = state.timeGrantIds.get(current.attempt); + submitting = true; + render(); + let timeAccepted = false; + try { + let response = await fetch(action === 'job-start' ? `/api/jobs/${current.key.slice(4)}/start` : action === 'job-cancel' ? `/api/jobs/${current.key.slice(4)}/cancel` : action === 'grant-time' ? attemptUrl(current, 'time') : `/api/campaigns/${encodeURIComponent(current.key)}/${action}`, { + method: 'POST', + headers: { 'content-type': 'application/json', 'x-stack-bench-token': state.csrfToken }, + body: JSON.stringify(action === 'grant-time' ? { grantId, minutes: Number(data.get('minutes')) } + : action === 'stop' ? { owner: data.get('owner') } + : {}), + }); + if (response.ok && resumeWithTime) { + timeAccepted = true; + response = await fetch(`/api/campaigns/${encodeURIComponent(current.key)}/resume`, { + method: 'POST', headers: { 'content-type': 'application/json', 'x-stack-bench-token': state.csrfToken }, body: '{}', + }); + } + if (response.ok) { + return void load(); + } + const failure = await response.json().catch(() => ({})) as { error?: string }; + if (response.status === 403) { state.csrfToken = ''; void load(); } + submittedForm.error = + (timeAccepted ? 'Time was added, but resume failed. ' : '') + + (failure.error || `Request failed (HTTP ${response.status}). Check campaign status before retrying.`); + } catch { + submittedForm.error = (timeAccepted ? 'Time was added. Could not confirm resume. ' : 'Could not confirm the request. ') + + 'Check campaign status before retrying.'; + } finally { + submitting = false; + render(); + } +} + +document.addEventListener('submit', event => { + const form = event.target; + if (!(form instanceof HTMLFormElement) || !form.dataset.run) return; + event.preventDefault(); + void post(form); +}); + +// Keep typed settings across background refreshes. +document.addEventListener('input', event => { + const field = event.target as HTMLInputElement; + if (field.form?.dataset.run === 'setup-review') { + state.setupRequest = field.name === 'workload' ? initialRun(state.setup!, field.value) : readRunForm(field.form, state.setup!); + if (field.name === 'workload' || field.name === 'level') render(); + return; + } + + if (field.name === 'minutes') { + state.timeGrantMinutes = field.value; + updateTimeTotal(field); + } + +}); + +document.addEventListener('keydown', event => { + if (route().view !== 'replay') return; + if (event.target instanceof Element + && event.target.closest('input, textarea, select, button, summary, [contenteditable]')) return; + if (event.key === 'ArrowRight') stepTo(1); + else if (event.key === 'ArrowLeft') stepTo(-1); + else if (event.key === ' ') { + event.preventDefault(); + if (playing) { + clearInterval(playing); + playing = 0; + } else playing = window.setInterval(() => stepTo(1), 600); + return; + } else return; + if (playing) { + clearInterval(playing); + playing = 0; + } +}); + +window.setInterval(() => { + for (const clock of document.querySelectorAll('[data-started-at]')) { + clock.textContent = elapsed(clock.dataset.startedAt ?? null, null); + } +}, 1000); +window.addEventListener('popstate', () => void load(true)); +document.addEventListener('visibilitychange', () => { + if (document.hidden) { + // Hidden tabs must not consume the browser's limited HTTP connections. + events?.close(); + events = null; + clearInterval(fallback); + fallback = 0; + } else { + subscribe(); + void load(); + } +}); +subscribe(); +void load(true); + +let transcriptLoading = false; +let transcriptReload = false; +async function readTranscript(force = false): Promise { + const current = route(); + if (document.hidden || current.tab !== 'transcript' || !current.attempt) return; + if (transcriptLoading) { transcriptReload ||= force; return; } + if (state.transcript.attempt !== current.attempt) state.transcript = { + attempt: current.attempt, session: '', before: undefined, page: null }; + const pane = document.querySelector('.transcript'); + if (!force && state.transcript.page && pane + && pane.scrollHeight - pane.scrollTop - pane.clientHeight >= 40) return; + const selected = state.transcript; + transcriptLoading = true; + try { + const query = new URLSearchParams({ session: selected.session }); + if (selected.before !== undefined) query.set('before', String(selected.before)); + const page = await read(attemptUrl(current, `transcript?${query}`)); + if (page && state.transcript === selected) selected.page = page; + } finally { + transcriptLoading = false; + if (transcriptReload) { + transcriptReload = false; + await readTranscript(true); + } + } +} +setInterval(() => { + if (document.hidden) return; + const current = route(); + if (current.plans) return; + if (current.key && state.sheets.get(current.key)?.status === 'running') { + void load(false, current.key, true); + } else if (!current.key && state.overview.some(entry => entry.status === 'running')) { + void load(false, undefined, true); + } else if (current.tab === 'transcript' && state.transcript.before === undefined) { + void readTranscript().then(render); + } +}, 5000); +document.addEventListener('change', event => { + const target = event.target; + if (target instanceof HTMLSelectElement && target.matches('[data-transcript-session]')) { + state.transcript = { ...state.transcript, session: target.value, before: undefined }; + void readTranscript(true).then(render); + } +}); +document.addEventListener('click', event => { + const target = event.target instanceof Element ? event.target.closest('[data-transcript-before], [data-transcript-latest]') : null; + if (!target) return; + state.transcript = { ...state.transcript, + session: state.transcript.page?.session ?? '', + before: target.hasAttribute('data-transcript-before') ? Number(target.dataset.transcriptBefore) : undefined }; + void readTranscript(true).then(() => { + render(); + const pane = document.querySelector('.transcript'); + if (pane && target.hasAttribute('data-transcript-latest')) pane.scrollTop = pane.scrollHeight; + }); +}); + +document.addEventListener('click', event => { + if (event.target instanceof Element && event.target.closest('[data-setup-edit]')) { + state.setupReview = null; state.form.error = ''; render(); + } +}); diff --git a/tools/stack-bench/dashboard/public/climb.ts b/tools/stack-bench/dashboard/public/climb.ts new file mode 100644 index 00000000000..4c1d7d72741 --- /dev/null +++ b/tools/stack-bench/dashboard/public/climb.ts @@ -0,0 +1,77 @@ +// The climb: one point per completed grade, unaided grades ringed, the current +// grade filled. Small in a lane or a sheet cell, large on the attempt page. + +import type { ClimbPoint } from '../dashboard-views.js'; +import { esc } from './format.js'; + +interface Plot { + x: number; + y: number; + point: ClimbPoint; +} + +function pointTitle(point: ClimbPoint): string { + return `${point.score} / ${point.max} points${point.unaided ? ' · First build at this level; earlier fixes and feedback retained' : ''}`; +} + +function plot(series: readonly ClimbPoint[], left: number, right: number, + top: number, bottom: number): Plot[] { + const span = Math.max(1, series.length - 1); + return series.map((point, index) => ({ + x: series.length === 1 ? (left + right) / 2 : left + (right - left) * index / span, + y: bottom - (bottom - top) * (point.max ? point.score / point.max : 0), + point, + })); +} + +function stepPath(plots: readonly Plot[]): string { + const head = plots[0]; + if (!head) return ''; + return plots.slice(1).reduce((path, item, index) => + `${path} L${item.x} ${plots[index]!.y} L${item.x} ${item.y}`, `M${head.x} ${head.y}`); +} + +// Full size: the same points with a band per depth or level, and a number at +// the first, the best and the current grade. +export function bigClimb(series: readonly ClimbPoint[], stage: (level: number) => string): string { + if (!series.length) return '

Awaiting first grade. The score history will appear here.

'; + const top = 10; + const bottom = 130; + const plots = plot(series, 100, 1010, top, bottom); + const bands: string[] = []; + let start = 0; + plots.forEach((item, index) => { + const next = plots[index + 1]; + if (next && next.point.level === item.point.level) return; + const level = item.point.level; + if (level !== null) { + const from = Math.max(60, plots[start]!.x - 40); + const width = Math.min(1050, item.x + 40) - from; + bands.push(`` + + `${esc(stage(level))}`); + } + start = index + 1; + }); + const line = stepPath(plots); + const first = plots[0]!; + const last = plots.at(-1)!; + const best = plots.reduce((top1, item) => item.y < top1.y ? item : top1, first); + const label = (item: Plot, tone: string): string => + `` + + `${Math.round(item.point.max ? 100 * item.point.score / item.point.max : 0)}`; + return `
Weighted score by completed grade. Each grade can cover a different scope.${bands.join('')}` + + [0, 50, 100].map(value => { + const y = bottom - (bottom - top) * value / 100; + return `` + + `${value}%`; + }).join('') + + `` + + `` + + plots.map(item => `${pointTitle(item.point)}`).join('') + + label(first, '#b6c0cf') + (best === first || best === last ? '' : label(best, '#b6c0cf')) + + (last === first ? '' : label(last, '#e6e9f0')) + '
'; +} diff --git a/tools/stack-bench/dashboard/public/fonts/inter-LICENSE.txt b/tools/stack-bench/dashboard/public/fonts/inter-LICENSE.txt new file mode 100644 index 00000000000..40589daa9de --- /dev/null +++ b/tools/stack-bench/dashboard/public/fonts/inter-LICENSE.txt @@ -0,0 +1,93 @@ +Copyright 2016 The Inter Project Authors (https://github.com/rsms/inter) Inter-Italic[opsz,wght].ttf: Copyright 2016 The Inter Project Authors (https://github.com/rsms/inter) + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/tools/stack-bench/dashboard/public/fonts/inter-latin-variable.woff2 b/tools/stack-bench/dashboard/public/fonts/inter-latin-variable.woff2 new file mode 100644 index 00000000000..d15208de03c Binary files /dev/null and b/tools/stack-bench/dashboard/public/fonts/inter-latin-variable.woff2 differ diff --git a/tools/stack-bench/dashboard/public/fonts/source-code-pro-LICENSE.txt b/tools/stack-bench/dashboard/public/fonts/source-code-pro-LICENSE.txt new file mode 100644 index 00000000000..046fc664900 --- /dev/null +++ b/tools/stack-bench/dashboard/public/fonts/source-code-pro-LICENSE.txt @@ -0,0 +1,93 @@ +Google Inc. + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/tools/stack-bench/dashboard/public/fonts/source-code-pro-latin-variable.woff2 b/tools/stack-bench/dashboard/public/fonts/source-code-pro-latin-variable.woff2 new file mode 100644 index 00000000000..bc303f50c5d Binary files /dev/null and b/tools/stack-bench/dashboard/public/fonts/source-code-pro-latin-variable.woff2 differ diff --git a/tools/stack-bench/dashboard/public/format.ts b/tools/stack-bench/dashboard/public/format.ts new file mode 100644 index 00000000000..d65b1183faa --- /dev/null +++ b/tools/stack-bench/dashboard/public/format.ts @@ -0,0 +1,120 @@ +// One spelling per value. Every figure the dashboard prints goes through here, +// so a percentage, a duration and a dash look the same on every page. + +import type { SheetAttempt } from '../dashboard-views.js'; +import type { CostEvidence } from '../../src/evidence/cost-proof.js'; +import { statusWord } from '../../src/evidence/status-words.js'; +import { outputSilentMinutes } from './metrics.js'; + +export { statusWord }; + +const SILENCE_MINUTES = 10; + +export const STACK_LABEL: Record = { spacetime: 'SpacetimeDB', + postgres: 'PostgreSQL', mongodb: 'MongoDB' }; +export const DASH = '—'; + +export function esc(value: unknown): string { + return String(value ?? '').replace(/[&<>"']/g, character => + ({ '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' })[character] ?? character); +} + +export function stackLabel(stack: string): string { + return STACK_LABEL[stack] ?? stack; +} + +export function metricLabel(label: string, description: string | undefined): string { + if (!description) return `${esc(label)}`; + const id = `help-${label.toLowerCase().replaceAll(' ', '-')}`; + return `` + + ``; +} + +export function pct(value: number | null | undefined): string { + return value == null ? DASH : `${Math.round(value)}%`; +} + +export function num(value: number | null | undefined): string { + return value == null ? DASH : String(Math.round(value)); +} + +// One value: the count and the total it is out of. +export function ratio(used: number | null | undefined, budget: number | null | undefined): string { + if (used == null) return DASH; + return budget == null ? String(used) : `${used} / ${budget}`; +} + +export function money(value: number | null | undefined): string { + if (value == null) return DASH; + return `$${value.toFixed(2)}`; +} + +export function spend(value: CostEvidence & { knownCostUsd?: number }, pending = false, liveSpend?: number): string { + return (liveSpend !== undefined + ? `~${money(liveSpend)}` + : value.status === 'unknown' ? value.knownCostUsd + ? `${money(value.knownCostUsd)} recorded` : 'Unknown' + : `${value.status === 'upper-bound' ? '≤' : ''}${money(value.costUsd)}`) + + (pending ? ' ' : ''); +} + +export function duration(seconds: number | null | undefined): string { + if (seconds == null) return DASH; + const minutes = Math.round(seconds / 60); + return minutes < 60 ? `${minutes}m` : `${Math.floor(minutes / 60)}h ${minutes % 60}m`; +} + +// Wall time for the current execution, separate from the measured run duration. +export function elapsed(startedAt: string | null, completedAt: string | null, + now = Date.now()): string { + if (startedAt === null) return DASH; + const start = Date.parse(startedAt); + const end = completedAt === null ? now : Date.parse(completedAt); + if (!Number.isFinite(start) || !Number.isFinite(end)) return DASH; + const seconds = Math.floor(Math.max(0, end - start) / 1000); + const minutes = Math.floor(seconds / 60); + return `${minutes >= 60 ? `${Math.floor(minutes / 60)}h ` : ''}${minutes % 60}m ${seconds % 60}s`; +} + +export function executionClock(startedAt: string | null, completedAt: string | null): string { + return `${elapsed(startedAt, completedAt)}`; +} + +export function since(value: string | null | undefined, now = Date.now()): string { + if (!value) return DASH; + const minutes = Math.max(0, Math.floor((now - Date.parse(value)) / 60000)); + if (minutes < 60) return `${minutes}m`; + if (minutes < 60 * 48) return `${Math.floor(minutes / 60)}h`; + return `${Math.floor(minutes / 1440)}d`; +} + +export function phrase(attempt: SheetAttempt, now = Date.now()): string { + const parts = [attempt.phase]; + const silent = outputSilentMinutes(attempt, now); + if (silent >= SILENCE_MINUTES) parts.push(`no agent activity observed for ${silent}m`); + return parts.join(' · '); +} + +// depth 3 · 1× / L1–L3 · 3× +export function shape(mode: string, levels: readonly number[], repetitions: number): string { + const depth = levels.length ? Math.max(...levels) : 0; + const span = mode === 'dependency' ? `depth ${depth}` + : levels.length > 1 ? `L${Math.min(...levels)}–L${depth}` : `L${depth}`; + return `${span} · ${repetitions}×`; +} + +export function modelLabel(model?: string): string { + return ({ 'claude-sonnet-5': 'Sonnet 5', 'claude-fable-5-1': 'Fable 5.1', 'claude-opus-5': 'Opus 5', 'gpt-5.6-sol': 'Sol', 'gpt-6-astra': 'Astra' } as Record)[model ?? ''] ?? model ?? ''; +} + +export function completionLabel(attempt: Pick, + completion: Pick, 'passed' | 'selected'> | null = attempt.completion): string { + if (attempt.excluded && attempt.status !== 'running' && attempt.status !== 'pending') { + return attempt.status === 'completed' ? 'Excluded' : 'Incomplete'; + } + return completion ? ratio(completion.passed, completion.selected) : DASH; +} + +export function runLabel(attempt: Pick, showRepetition = true): string { + return `${modelLabel(attempt.model)}${attempt.effort ? ` (${attempt.effort})` : ''}${showRepetition ? ` · Rep ${attempt.repetition}` : ''}`; +} diff --git a/tools/stack-bench/dashboard/public/graph.ts b/tools/stack-bench/dashboard/public/graph.ts new file mode 100644 index 00000000000..1c130c4a51a --- /dev/null +++ b/tools/stack-bench/dashboard/public/graph.ts @@ -0,0 +1,95 @@ +// One graph for the campaign: columns are depth, bands are questlines, edges +// are the catalog's own dependencies. Every stack builds the same catalog, so a +// node carries one dot per stack in fixed order. The renderer takes one +// node-status snapshot per stack, which is what the replay feeds it per step. + +import type { CampaignProgression } from '../dashboard-views.js'; +import { esc, stackLabel, statusWord } from './format.js'; + +export interface GraphStack { + stack: string; + statuses: readonly string[]; +} + +const DOT: Record = { passed: 'p', active: 'a', working: 'a', failed: 'f', + blocked: 'b', locked: 'o' }; +const DOT_START = 180; +const DOT_SPACING = 14; +const ROW = 30; + +interface Placed { + x: number; + y: number; + index: number; +} + +export function graph(view: CampaignProgression, stacks: readonly GraphStack[]): string { + if (!view.nodes.length) return '

No feature graph is available.

'; + const depths = view.depths; + const nodeWidth = DOT_START + Math.max(1, stacks.length) * DOT_SPACING; + const columnWidth = nodeWidth + 60; + const width = 150 + Math.max(1, depths.length) * columnWidth - 40; + const placed = new Map(); + const bands: string[] = []; + let top = 20; + for (const questline of view.questlines) { + const nodes = view.nodes.filter(node => node.questline === questline.id); + if (!nodes.length) continue; + const used = new Map(); + let rows = 0; + for (const node of nodes) { + const row = used.get(node.depth) ?? 0; + used.set(node.depth, row + 1); + rows = Math.max(rows, row + 1); + placed.set(node.id, { x: 150 + Math.max(0, depths.indexOf(node.depth)) * columnWidth, + y: top + 8 + row * ROW, index: view.nodes.indexOf(node) }); + } + const height = rows * ROW + 16; + bands.push(`${esc(questline.title.length > 19 ? `${questline.title.slice(0, 18)}…` : questline.title)}${esc(questline.title)}`); + top += height; + bands.push(``); + } + const failed = (index: number): boolean => + stacks.some(entry => entry.statuses[index] === 'failed'); + const blocked = (index: number): boolean => + stacks.some(entry => entry.statuses[index] === 'blocked'); + const edges = view.nodes.flatMap(node => { + const target = placed.get(node.id); + if (!target) return []; + return node.dependencies.flatMap(id => { + const source = placed.get(id); + if (!source) return []; + const cut = failed(source.index) || blocked(target.index); + return [``]; + }); + }); + const nodes = view.nodes.map(node => { + const at = placed.get(node.id); + if (!at) return ''; + const dots = stacks.map((entry, column) => + `` + + (entry.statuses[at.index] === 'passed' + ? `` : '')).join(''); + const hover = stacks.map(entry => + `${stackLabel(entry.stack)} ${statusWord(entry.statuses[at.index] ?? 'locked')}`).join(' · '); + return `${esc(`${node.title} · ${hover}`)}` + + `` + + `${esc(node.title.length > 22 + ? `${node.title.slice(0, 21)}…` : node.title)}${dots}`; + }); + const columns = depths.map((depth, index) => + `depth ${depth}`).join(''); + const order = stacks.map(entry => stackLabel(entry.stack)).join(', '); + const description = view.nodes.map((node, index) => `${node.title}: ${stacks.map(entry => + `${stackLabel(entry.stack)} ${statusWord(entry.statuses[index] ?? 'locked')}`).join(', ')}`).join('. '); + const key = [['p', 'Passed'], ['a', 'Active'], ['f', 'Failed'], ['b', 'Blocked'], ['o', 'Locked']] + .map(([tone, label]) => `${label}`).join(''); + return `
${stacks.length > 1 ? `

Feature dots, left to right: ${esc(order)}.

` : ''}${key}
` + + `
` + + `` + + `Feature dependencies and stack status${esc(description)}` + + `${bands.join('')}${columns}${edges.join('')}${nodes.join('')}
`; +} diff --git a/tools/stack-bench/dashboard/public/index.html b/tools/stack-bench/dashboard/public/index.html new file mode 100644 index 00000000000..e94a45b9a35 --- /dev/null +++ b/tools/stack-bench/dashboard/public/index.html @@ -0,0 +1,15 @@ + + + + + + + + Stack Bench + + + + + +
Loading Stack Bench…
+ diff --git a/tools/stack-bench/dashboard/public/metrics.ts b/tools/stack-bench/dashboard/public/metrics.ts new file mode 100644 index 00000000000..8177b03d291 --- /dev/null +++ b/tools/stack-bench/dashboard/public/metrics.ts @@ -0,0 +1,202 @@ +import type { CampaignRunLevelResult, CampaignRunResult, DependencyProgress } + from '../../src/campaigns/campaign-inspection.js'; +import type { CostEvidence } from '../../src/evidence/cost-proof.js'; +import type { CheckCompletion } from '../../src/evidence/check-completion.js'; + +// The dashboard's vocabulary in one place: First builds, Score, Repairs, Regressions, +// Stalling and Excluded are defined here and nowhere else, so the server-rendered +// sheet and the browser read the same numbers from the same evidence. + +const EXCLUDED_OUTCOMES = new Set(['harness_failure', 'inconclusive', 'ungraded', 'contaminated']); +const SILENCE_MINUTES = 10; + +export interface MetricExecution { + outcome: string | null; + reason: string | null; +} + +export interface MetricAttempt { + id: string; + stack: string; + status: string; + repetition?: number; + logUpdatedAt?: string | null; + activityUpdatedAt?: string | null; + paused?: boolean; + execution: MetricExecution | null; + result: CampaignRunResult | null; + dependency: DependencyProgress | null; + spend?: CostEvidence; + measuredCost?: CostEvidence; + completion?: CheckCompletion | null; + comparisonKey?: string; +} + +export interface AttemptMetrics { + first: number | null; + final: number; + repairs: number; + spend: number | null; + duration: number | null; + scope: string; + abortedFirst: number; + raw: { + first: { score: number; max: number } | null; + final: { score: number; max: number } | null; + }; +} + +export interface ComparisonEntry { + stack: string; + runs: Array<{ attempt: Attempt; metrics: AttemptMetrics }>; + excluded: Array<{ attempt: Attempt; reason: string }>; + pending: number; + spendSoFar: number | null; + abortedFirst: number; +} + +export type ComparisonRow = ComparisonEntry & { + n: number; scopes: string[]; first: number | null; final: number | null; + repairs: number | null; spend: number | null; duration: number | null; + costPerValidRun: number | null; + firstRange: { min: number; max: number } | null; + spendRange: { min: number; max: number } | null; + durationRange: { min: number; max: number } | null; +}; + +export function median(values: readonly number[]): number | null { + if (!values.length) return null; + const sorted = [...values].sort((left, right) => left - right); + const middle = Math.floor(sorted.length / 2); + return sorted.length % 2 ? sorted[middle]! : (sorted[middle - 1]! + sorted[middle]!) / 2; +} + +export function attemptSpend(attempt: MetricAttempt): number | null { + return attempt.spend?.status === 'exact' ? attempt.spend.costUsd : null; +} + +// An ungraded first build has no score; it is not a zero. +export function attemptMetrics(attempt: MetricAttempt): AttemptMetrics | null { + const run = attempt.result; + if (!run || run.unreadable) return null; + const dependency = attempt.dependency; + if (dependency) { + const score = dependency.score; + const unique = score?.uniqueChecks; + if (score?.status !== 'final' || unique?.percentage == null) return null; + const available = unique.availablePoints ?? 0; + return { + first: run.firstBuildRate ?? null, + // Final completion counts each selected graph point once. First builds + // instead sum the cumulative scored scope at each depth. + final: unique.percentage / 100, + repairs: dependency.history?.repairAttempts ?? 0, + spend: attempt.measuredCost?.status === 'exact' ? attempt.measuredCost.costUsd : null, + duration: run.activeDurationSec ?? null, + scope: `${attempt.comparisonKey ?? ''}:dependency:${dependency.nodes.length}:${available}`, + abortedFirst: 0, + raw: { first: null, final: unique.passedPoints == null + ? null : { score: unique.passedPoints, max: available } }, + }; + } + type FinalLevel = CampaignRunLevelResult & { finalScore: { score: number; max: number } }; + type ScoredLevel = FinalLevel & { firstScore: { score: number; max: number } }; + const levels = (run.levels ?? []) + .filter((level): level is FinalLevel => level.finalScore !== null); + if (!levels.length) return null; + const sum = (list: readonly Level[], + pick: (level: Level) => number): number => list.reduce((total, item) => total + pick(item), 0); + const scored = levels.filter((level): level is ScoredLevel => + level.firstScore !== null && level.firstAbort === null); + const abortedFirst = levels.filter(level => level.firstAbort).length; + const firstMax = sum(scored, level => level.firstScore.max); + const finalMax = sum(levels, level => level.finalScore.max); + return { + first: run.firstBuildRate ?? null, + final: sum(levels, level => level.finalScore.score) / finalMax, + repairs: sum(levels, level => level.used ?? 0), + spend: attempt.measuredCost?.status === 'exact' ? attempt.measuredCost.costUsd : null, + duration: run.activeDurationSec ?? null, + scope: `${attempt.comparisonKey ?? ''}:sequential:${levels.map(level => level.level).join(',')}`, + abortedFirst, + // Do not show a partial first-build sum when the complete rate is unknown. + raw: { first: run.firstBuildRate != null && firstMax ? { score: sum(scored, l => l.firstScore.score), max: firstMax } : null, + final: { score: sum(levels, l => l.finalScore.score), max: finalMax } }, + }; +} + +export function attemptExcluded(attempt: MetricAttempt): string | null { + const outcome = attempt.execution?.outcome ?? attempt.result?.outcome; + if (attempt.status === 'invalid') return attempt.execution?.reason ?? outcome ?? 'excluded'; + if (attempt.result?.unreadable && attempt.status !== 'running') return `Result validation failed: ${attempt.result.unreadable}`; + // 'ungraded' on an attempt still running means "not yet", not "thrown out". + if (outcome && EXCLUDED_OUTCOMES.has(outcome) && attempt.status === 'completed') return outcome; + return null; +} + +// Compare results only when they share the same recorded test plan. +export function compareCampaign(campaign: { + attempts?: readonly Attempt[]; +}): { rows: Array>; usable: Array>; + priced: Array>; burn: Map; + mixedScope: boolean; comparable: boolean } { + const byStack = new Map>(); + const unknownSpend = new Set(); + for (const attempt of campaign.attempts ?? []) { + const entry = byStack.get(attempt.stack) + ?? { stack: attempt.stack, runs: [], excluded: [], pending: 0, spendSoFar: null, abortedFirst: 0 }; + byStack.set(attempt.stack, entry); + // Excluded attempts still contribute to actual spend. + const incurred = attemptSpend(attempt); + if (incurred === null) unknownSpend.add(attempt.stack); + else entry.spendSoFar = (entry.spendSoFar ?? 0) + incurred; + const reason = attemptExcluded(attempt); + if (reason) { entry.excluded.push({ attempt, reason }); continue; } + const metrics = attempt.status === 'completed' ? attemptMetrics(attempt) : null; + if (metrics) { + entry.runs.push({ attempt, metrics }); + entry.abortedFirst += metrics.abortedFirst; + } else entry.pending += 1; + } + const rows = [...byStack.values()] + .map(entry => { + const pick = (key: 'first' | 'final' | 'repairs' | 'spend' | 'duration'): number[] => + entry.runs.map(run => run.metrics[key]).filter((value): value is number => value !== null); + const range = (values: readonly number[]): { min: number; max: number } | null => + values.length ? { min: Math.min(...values), max: Math.max(...values) } : null; + const spend = pick('spend'); + const duration = pick('duration'); + const first = pick('first'); + const scopes = [...new Set(entry.runs.map(run => run.metrics.scope))].sort(); + return { ...entry, spendSoFar: unknownSpend.has(entry.stack) ? null : entry.spendSoFar, + n: entry.runs.length, scopes, + first: scopes.length === 1 ? median(first) : null, firstRange: range(first), + final: scopes.length === 1 ? median(pick('final')) : null, + repairs: scopes.length === 1 ? median(pick('repairs')) : null, + spend: scopes.length === 1 ? median(spend) : null, spendRange: scopes.length === 1 ? range(spend) : null, + costPerValidRun: scopes.length === 1 && spend.length > 0 && spend.length === entry.runs.length + ? spend.reduce((total, cost) => total + cost, 0) / spend.length : null, + duration: scopes.length === 1 ? median(duration) : null, + durationRange: scopes.length === 1 ? range(duration) : null }; + }); + const usable = rows.filter(row => row.n > 0); + const scopes = new Set(usable.flatMap(row => row.scopes)); + const priced = usable.filter(row => row.spend != null); + return { rows, usable, priced, + burn: new Map(rows.map(entry => [entry.stack, entry.spendSoFar])), + mixedScope: scopes.size > 1, + comparable: priced.length > 1 && scopes.size === 1 }; +} + +export function outputSilentMinutes(attempt: Pick, now = Date.now()): number { + if (attempt.status !== 'running' || attempt.paused || !attempt.activityUpdatedAt) return 0; + const updated = Date.parse(attempt.activityUpdatedAt); + return Number.isFinite(updated) ? Math.max(0, Math.floor((now - updated) / 60000)) : 0; +} + +// Flag observed agent inactivity, never infer it from controller output or scores. +export function attemptStalling(attempt: Pick, + now = Date.now()): boolean { + return outputSilentMinutes(attempt, now) >= SILENCE_MINUTES; +} diff --git a/tools/stack-bench/dashboard/public/progress-chart.ts b/tools/stack-bench/dashboard/public/progress-chart.ts new file mode 100644 index 00000000000..fe106c73bc2 --- /dev/null +++ b/tools/stack-bench/dashboard/public/progress-chart.ts @@ -0,0 +1,135 @@ +import type { CampaignProgression, CampaignSheet } from '../dashboard-views.js'; +import { duration, esc, runLabel, stackLabel } from './format.js'; + +export function progressChart(sheet: CampaignSheet, progression: CampaignProgression | null, + metric: 'completion' | 'cost' | 'distribution' = 'completion', view = 'grid', hidden: ReadonlySet = new Set(), unit: 'checks' | 'features' = 'features'): string { + const tracks = metric === 'distribution' ? sheet.stacks.flatMap(stack => stack.attempts.flatMap(attempt => { + const rate = unit === 'features' ? attempt.featureCompletion?.rate : attempt.completion?.rate; + return attempt.status === 'completed' && !attempt.excluded && rate != null && Number.isFinite(rate) + ? [{ stack: stack.stack, attempt, points: [{ elapsed: 0, value: rate * 100, upper: false }] }] : []; + })) : sheet.stacks.flatMap(stack => stack.attempts.map(attempt => + progression?.stacks.find(track => track.attemptId === attempt.id) + ?? { stack: stack.stack, attemptId: attempt.id, steps: [], costs: [], liveCosts: undefined })).flatMap(track => { + const attempt = sheet.stacks.find(stack => stack.stack === track.stack)?.attempts + .find(candidate => candidate.id === track.attemptId); + const start = Date.parse(attempt?.executionStartedAt ?? ''); + if (!attempt || !Number.isFinite(start)) return []; + const observations = (metric === 'cost' ? (track.liveCosts?.map(point => ({ + completedAt: point.completedAt, value: point.costUsd, upper: false, + })) ?? (track.costs ?? []).map(point => ({ + completedAt: point.completedAt, value: point.cost.costUsd, upper: point.cost.status === 'upper-bound', + }))) : track.steps.map(step => ({ completedAt: step.completedAt, + value: (unit === 'features' ? step.featureCompletion : step.completion) == null ? null + : (unit === 'features' ? step.featureCompletion! : step.completion!) * 100, upper: false }))).flatMap(step => { + const elapsed = (Date.parse(step.completedAt ?? '') - start) / 1000; + return Number.isFinite(elapsed) && elapsed >= 0 && step.value != null + && Number.isFinite(step.value) && step.value >= 0 + ? [{ elapsed, value: step.value, upper: step.upper }] : []; + }).sort((a, b) => a.elapsed - b.elapsed); + if (metric === 'cost' && attempt.executionCost) { + const liveTotal = track.liveCosts?.at(-1)?.costUsd; + const total = liveTotal ?? attempt.executionCost.costUsd; + const end = Date.parse(attempt.executionCompletedAt ?? attempt.activityUpdatedAt ?? attempt.logUpdatedAt ?? ''); + const elapsed = (end - start) / 1000; + if (total != null && Number.isFinite(total) && Number.isFinite(elapsed) && elapsed >= 0) { + // The sheet owns the total; histories can arrive in a different refresh. + while (observations.length && observations.at(-1)!.elapsed >= elapsed) observations.pop(); + observations.push({ elapsed, value: total, upper: liveTotal === undefined && attempt.executionCost.status === 'upper-bound' }); + } + } + const points = [{ elapsed: 0, value: 0, upper: false }, ...observations]; + return observations.length ? [{ stack: track.stack, attempt, points }] : []; + }); + const unitDescription = unit === 'features' + ? 'Features fully passed out of all selected features. A feature passes only when all its selected checks pass, including production guarantees.' + : 'Accepted checks passed out of all selected checks.'; + const label = metric === 'distribution' ? 'Completion distribution' : metric === 'cost' ? 'Cost' : 'Completion'; + const description = metric === 'distribution' + ? `One point per eligible completed run, grouped by stack. ${unitDescription} Running and excluded runs are not plotted.` + : metric === 'cost' + ? 'Current-execution cost, including repairs and excluded runs. Earlier executions remain in Total spend; Cost per valid run also includes explicit resume history. Live estimates use reported response usage; final receipts replace estimates. Other runs show saved grade checkpoints. Subscription costs use the pinned API-equivalent price snapshot, not invoice charges. Unknown costs are not plotted; upper bounds are labelled. Time starts at the current execution. Lines connect observations; intermediate values are not measured.' + : `${unitDescription} Each point is a saved grade. Zero marks run start. Each line is one repetition; elapsed time starts at that run. Excluded runs are labelled. Lines can fall after regressions. Intermediate values are not measured.`; + const heading = `

${label}${metric === 'distribution' ? '' : ' over time'}

' + + '' + + '
'; + const valueLabel = (value: number, upper = false, decimals = 1) => metric === 'cost' + ? `${upper ? '≤' : ''}$${value.toFixed(2)}` : `${value.toFixed(decimals)}%`; + const brandColors: Record = { spacetime: '#4cf490', mongodb: '#b45af2', postgres: '#336791' }; + const color = (stack: string) => brandColors[stack] + ?? `hsl(${Array.from(stack).reduce((hash, char) => (hash * 31 + char.charCodeAt(0)) % 360, 0)},65%,65%)`; + const marker = (repetition: number, x: number, y: number, title = '') => { + const shape = (repetition - 1) % 3; + return shape === 1 ? `${title}` + : shape === 2 ? `${title}` + : `${title}`; + }; + const controls = `
` + sheet.stacks.map(stack => { + const shown = stack.attempts.filter(attempt => !hidden.has(attempt.id)).length; + return `
` + + `` + + '
' + stack.attempts.map(attempt => { + const point = tracks.find(track => track.attempt.id === attempt.id)?.points.at(-1); + const label = runLabel(attempt, sheet.repetitions > 1) + + (point ? ` · ${metric === 'cost' && attempt.liveSpend !== undefined ? '~' : ''}${valueLabel(point.value, point.upper, 0)}` : ''); + const status = attempt.excluded || attempt.status === 'invalid' ? ' · Excluded' : ''; + return ``; + }).join('') + '
'; + }).join('') + '
'; + const visible = tracks.filter(track => !hidden.has(track.attempt.id)); + if (!visible.length) return `
${heading}${controls}

${tracks.length > 0 && tracks.every(track => hidden.has(track.attempt.id)) ? 'Select a run to show its progress.' : metric === 'distribution' ? 'Awaiting first completed run.' : metric === 'cost' ? 'Awaiting first timed cost receipt.' : 'Awaiting first timed grade.'}

`; + if (metric === 'distribution') { + const axisLeft = 150; + const position = (value: number) => axisLeft + (910 - axisLeft) * value / 100; + const rowHeight = Math.max(70, ...sheet.stacks.map(stack => stack.attempts.length * 20 + 24)); + const bottom = sheet.stacks.length * rowHeight + 24; + const ticks = [0, 25, 50, 75, 100].map(value => + `` + + `${value}%`).join(''); + const rows = sheet.stacks.map((stack, index) => { + const center = 24 + rowHeight * (index + 0.5); + const points = visible.filter(track => track.stack === stack.stack); + return `${esc(stackLabel(stack.stack))}` + + points.map(track => { + const value = track.points[0]!.value; + const at = center + (stack.attempts.findIndex(a => a.id === track.attempt.id) - (stack.attempts.length - 1) / 2) * 20; + const label = `${stackLabel(stack.stack)} · ${runLabel(track.attempt)}: ${valueLabel(value)}${track.attempt.excluded ? ' · Excluded' : ''}`; + return `` + + `${esc(label)}` + + marker(track.attempt.repetition, position(value), at) + + `${esc(runLabel(track.attempt))}` + + `${valueLabel(value, false, 0)}`; + }).join(''); + }).join(''); + return `
${heading}${controls}
` + + `${description}${ticks}${rows}
`; + } + const ceiling = metric === 'cost' ? Math.max(0.01, ...tracks.flatMap(track => track.points.map(point => point.value))) : 100; + const maximum = Math.max(60, ...tracks.flatMap(track => track.points.map(point => point.elapsed))); + const left = metric === 'cost' ? 80 : 48; + const x = (seconds: number) => left + (948 - left) * seconds / maximum; + const y = (value: number) => 190 - 160 * value / ceiling; + const grid = [0, 0.25, 0.5, 0.75, 1].map(part => part * ceiling).map(value => + `${valueLabel(value, false, 0)}`).join(''); + const ticks = [0, 0.25, 0.5, 0.75, 1].map(part => + `${esc(part ? duration(part * maximum) : '0')}`).join(''); + const lines = visible.map(({ stack, attempt, points }) => { + // Saved observations are not continuous measurements. Stop at the last receipt. + let path = ''; + const marks = points.map((point, index) => { + path += index ? ` L${x(point.elapsed)} ${y(point.value)}` : `M${x(point.elapsed)} ${y(point.value)}`; + return marker(attempt.repetition, x(point.elapsed), y(point.value), `${esc(stackLabel(stack))} · ${esc(runLabel(attempt))}: ${valueLabel(point.value, point.upper)} at ${esc(duration(point.elapsed))}${index === 0 ? (metric === 'cost' ? ' · Run start; no recorded cost' : ' · Run start; no checks graded') : ''}${attempt.excluded ? ' · Excluded' : ''}`); + }).join(''); + return `${marks}`; + }).join(''); + return `
${heading}${controls}
` + + `${description}${grid}${ticks}${lines}Elapsed run time
` + + '
'; +} diff --git a/tools/stack-bench/dashboard/public/spacetimedb-mark.svg b/tools/stack-bench/dashboard/public/spacetimedb-mark.svg new file mode 100644 index 00000000000..f7957efa1ed --- /dev/null +++ b/tools/stack-bench/dashboard/public/spacetimedb-mark.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/tools/stack-bench/dashboard/public/styles.css b/tools/stack-bench/dashboard/public/styles.css new file mode 100644 index 00000000000..e0e567de862 --- /dev/null +++ b/tools/stack-bench/dashboard/public/styles.css @@ -0,0 +1,343 @@ +/* Stack Bench dashboard: compact tables, sentence-case labels, and consistent spacing. + * Brand colors identify stacks in charts. Status: pulsing green active, static green checks passed, + * red failed, yellow warning, gray pending. Completion alone is not success. */ + +@font-face { + font-family: 'Inter Variable'; + font-style: normal; + font-display: swap; + font-weight: 100 900; + src: url(/fonts/inter-latin-variable.woff2) format('woff2-variations'); +} +@font-face { + font-family: 'Source Code Pro Variable'; + font-style: normal; + font-display: swap; + font-weight: 200 900; + src: url(/fonts/source-code-pro-latin-variable.woff2) format('woff2-variations'); +} + +:root { + --green: #4cf490; --green-25: #4cf49040; --green-10: #4cf4901a; + --active: var(--green); --active-ring: var(--green-25); + --yellow: #fbdc8e; --yellow-25: #fbdc8e40; --yellow-10: #fbdc8e1a; + --red: #ff4c4c; + --n1: #e6e9f0; --n2: #ced3e0; --n3: #b6c0cf; --n4: #8d98a5; --n5: #363840; --n7: #050505; + --shade1: #162d38; --shade4: #121e24; --shade5: #0f191f; --shade6: #0e161a; + --shade7: #0b1114; --shade8: #0b0e12; + --sans: 'Inter Variable', Inter, ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif; + --mono: 'Source Code Pro Variable', 'Source Code Pro', ui-monospace, SFMono-Regular, Consolas, monospace; + color-scheme: dark; +} + +* { box-sizing: border-box; } +body { margin: 0; background: var(--shade7); color: var(--n3); font: 14px/1.5 var(--sans); } +a { color: var(--n1); } +:focus-visible { outline: 2px solid var(--green); outline-offset: 2px; } +::selection { background: var(--green-25); } + +.topbar { display: flex; align-items: center; gap: 22px; height: 48px; padding: 0 24px; border-bottom: 1px solid var(--shade4); } +.brand { display: flex; align-items: center; gap: 10px; color: var(--n1); text-decoration: none; } +.brand b { font: 600 12px/1 var(--mono); letter-spacing: .1em; } +.btn { display: inline-flex; align-items: center; min-height: 36px; padding: 0 14px; border-radius: 4px; border: 1px solid var(--shade1); color: var(--n1); background: transparent; font: 500 13px/1 var(--sans); cursor: pointer; list-style: none; } +.nav { display: flex; gap: 2px; } +.nav a { padding: 8px 10px; border-radius: 4px; color: var(--n4); text-decoration: none; font: 500 12.5px var(--sans); } +.nav a.on { color: var(--n1); background: var(--shade5); } +.btn.primary { background: var(--green); border-color: var(--green); color: var(--n7); text-decoration: none; } +.tools { display: flex; align-items: center; gap: 10px; margin-left: auto; } +.files { position: relative; z-index: 10; } +.files summary::-webkit-details-marker { display: none; } +.files div { position: absolute; right: 0; top: 36px; display: grid; gap: 2px; padding: 8px 10px; background: var(--shade6); border: 1px solid var(--shade1); border-radius: 4px; } +.files div a { padding: 6px 2px; white-space: nowrap; color: var(--n2); font: 12px var(--mono); text-decoration: none; } +.page { max-width: 1600px; margin-inline: auto; padding: 22px 24px 40px; } +.crumbs { color: var(--n4); font: 12px var(--mono); margin-bottom: 8px; } +.crumbs a { color: var(--n4); text-decoration: none; } +.crumbs b { color: var(--n2); font-weight: 500; } +.title { flex-wrap: wrap; display: flex; align-items: center; gap: 12px; margin-bottom: 16px; } +.title h2 { margin: 0; color: var(--n1); font: 600 25px/28px var(--sans); letter-spacing: -.01em; } +.title h2 span { color: var(--n4); font-weight: 400; } +.label { color: var(--n4); font: 500 12px/1.4 var(--sans); } +.state { color: var(--n4); font: 500 13px var(--sans); white-space: nowrap; } +.state.run { color: var(--active); } +.state.done { color: var(--n2); } +.state.warn { color: var(--yellow); } +.state.idle { color: var(--n4); } + +/* live lanes: stack, score, climb, phase */ +.live { border: 1px solid var(--shade4); border-radius: 4px; background: var(--shade6); margin-bottom: 18px; } +.live-head { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; min-height: 44px; padding: 8px 16px; border-bottom: 1px solid var(--shade4); } +.live-head b { color: var(--n1); font-size: 15px; font-weight: 600; } +.lane { display: grid; grid-template-columns: minmax(220px, 1.6fr) minmax(80px, .4fr) minmax(100px, .5fr) minmax(180px, 1fr); gap: 20px; align-items: center; padding: 14px 16px; border-top: 1px solid var(--shade4); } +.lane > * { min-width: 0; } +.lane-repetition { white-space: nowrap; } +.lane-variant { margin-top: 5px; font-size: 12px; overflow-wrap: anywhere; color: var(--n2); } +.lane-metric { display: grid; gap: 6px; font-variant-numeric: tabular-nums; } +.lane-label { font-size: 12px; color: var(--n2); } +.lane:first-of-type { border-top: 0; } +.lane .who { color: var(--n1); font-weight: 600; } +.lane .big { color: var(--n1); font: 600 26px/1 var(--sans); letter-spacing: -.02em; } +.lane .phase { font-size: 13px; overflow-wrap: anywhere; } +.lane .phase.warn { color: var(--yellow); } + +/* campaigns table */ +.tablewrap { border: 1px solid var(--shade4); border-radius: 4px; background: var(--shade6); overflow: hidden; } +.toolbar { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; min-height: 44px; padding: 6px 12px; border-bottom: 1px solid var(--shade4); } +.chip { height: 24px; padding: 0 10px; border-radius: 4px; border: 1px solid var(--shade1); color: var(--n3); font: 500 12px/22px var(--sans); text-decoration: none; } +.chip.on { background: var(--shade1); color: var(--n1); } +.chip.sm { height: 24px; line-height: 22px; font-size: 12px; padding: 0 8px; } +.wrap { overflow-x: auto; } +table.runs { width: 100%; border-collapse: collapse; font-size: 13px; } +table.runs th, table.runs td { padding: 0 14px; height: 40px; text-align: left; vertical-align: middle; border-bottom: 1px solid var(--shade4); white-space: nowrap; } +table.runs thead th { color: var(--n4); font: 600 12px/1.4 var(--sans); height: 36px; } +table.runs tbody tr:last-child td { border-bottom: 0; } +table.runs tbody tr:hover td { background: var(--shade5); } +table.runs td.name a { color: var(--n1); font-weight: 600; text-decoration: none; } +table.runs td.shape { color: var(--n4); font: 12px var(--mono); } +table.runs td.stack { text-align: right; font: 13px var(--mono); font-variant-numeric: tabular-nums; color: var(--n1); width: 128px; } +table.runs th.stack:first-of-type, table.runs td.stack:first-of-type { border-left: 1px solid var(--shade4); } +table.runs td.stack.na { color: var(--n4); } +table.runs td.stack u { text-decoration-color: var(--green); text-underline-offset: 5px; text-decoration-thickness: 2px; } +table.runs th.when, table.runs td.when { color: var(--n4); font: 12px var(--mono); text-align: right; } +table.runs thead th.stack { text-align: right; } +table.runs thead th.when { color: var(--n4); font: 600 12px/1.4 var(--sans); } + +/* saved plans and shared controls */ +table.plans th.stack, table.plans td.stack { width: auto; } +table.plans td.name { color: var(--n1); font-weight: 600; min-width: 240px; max-width: 360px; white-space: normal; padding-block: 10px; overflow-wrap: anywhere; } +.secret input, .transcript-controls select, .transcript-controls button { height: 30px; padding: 0 10px; border: 1px solid var(--shade1); border-radius: 4px; background: var(--shade7); color: var(--n1); font: 13px var(--mono); } +.secret { display: flex; align-items: center; gap: 8px; } +.secret input { width: 168px; } +.err { color: var(--red); font: 12.5px var(--sans); align-self: center; } + +/* campaign sheet: stacks across, facts down */ +.page > h3 { margin: 28px 0 12px; font-size: 15px; font-weight: 600; color: var(--n1); } +.facts { display: flex; flex-wrap: wrap; gap: 1px; margin: 0 0 16px; background: var(--shade4); border: 1px solid var(--shade4); border-radius: 4px; overflow: hidden; } +.facts div { flex: 1 1 168px; align-content: start; display: grid; gap: 5px; min-width: 0; padding: 9px 12px; background: var(--shade6); } +.facts b { color: var(--n2); font: 500 12px/1.5 var(--mono); overflow-wrap: anywhere; } +.sheet { width: 100%; border-collapse: collapse; background: var(--shade6); } +.sheet th, .sheet td { min-width: 185px; padding: 8px 16px; text-align: left; vertical-align: middle; border: 1px solid var(--shade4); } +.sheet th:first-child { min-width: 190px; width: 190px; } +.sheet .k { color: var(--n4); font: 500 13px/1.4 var(--sans); } +.sheet .h { height: 48px; color: var(--n1); font-size: 15px; font-weight: 600; } +.sheet .h a { text-decoration: none; } +.sheet .v { color: var(--n1); font: 13px var(--mono); font-variant-numeric: tabular-nums; } +.sheet .v i, .checks .group i { color: var(--n4); font-style: normal; margin-left: 6px; } +.sheet .big { color: var(--n1); font: 600 30px/1 var(--sans); letter-spacing: -.02em; } +.sheet .q { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; min-height: 36px; padding-block: 6px; } +.sheet .q.k { display: table-cell; text-transform: none; letter-spacing: 0; font: 12.5px var(--sans); color: var(--n3); } +.sheet .q .pct { margin-left: auto; color: var(--n4); font: 11.5px var(--mono); font-variant-numeric: tabular-nums; } +.sheet .q .pct.full { color: var(--green); } + +.evhead { display: flex; flex-wrap: wrap; gap: 0; padding: 0; } +.evhead .ev { display: grid; gap: 5px; padding: 8px 16px; border-left: 1px solid var(--shade4); min-height: 48px; min-width: 130px; } +.evhead .ev:first-child { border-left: 0; } +.dot { width: 9px; height: 9px; border-radius: 50%; background: var(--shade1); flex: 0 0 auto; } +.dot.p { position: relative; background: var(--green); } +.dot.p::after { content: ""; position: absolute; left: 3px; top: 1px; width: 2px; height: 4px; border: solid var(--shade7); border-width: 0 1.5px 1.5px 0; transform: rotate(45deg); } +.dot.a { background: var(--active); box-shadow: 0 0 0 2px var(--active-ring); } +.dot.f { background: var(--red); } +.dot.b { background: transparent; border: 1.5px solid var(--red); } +.dot.o { background: transparent; border: 1.5px solid var(--n4); } + +/* graph */ +.dag { display: block; height: auto; } +.dag .band { font: 11px var(--mono); fill: var(--n4); } +.dag .col { font: 500 10.5px var(--mono); fill: var(--n4); letter-spacing: .08em; text-transform: uppercase; } +.dag .sep { stroke: var(--shade4); } +.dag .e { fill: none; stroke: var(--shade1); stroke-width: 1.1; opacity: .8; } +.dag .e.cut { stroke: var(--red); stroke-dasharray: 3 4; opacity: .7; } +.dag .n rect { fill: var(--shade5); stroke: var(--shade1); } +.dag .n text { font: 12px var(--mono); fill: var(--n2); } +.dag .d { fill: var(--shade1); } +.dag .d.p { fill: var(--green); } +.dag .d.a { fill: var(--active); } +.dag .d.f { fill: var(--red); } +.dag .d.b { fill: none; stroke: var(--red); stroke-width: 1.4; } +.dag .d.o { fill: none; stroke: var(--n4); stroke-width: 1.4; } + +/* replay */ +.replay { min-height: 40px; padding: 6px 16px; } +.strip { display: block; width: 100%; height: 28px; } +.strip .st { fill: var(--n4); } +.strip .st.b, .strip .st.r { fill: var(--active); } +.strip .st.g { fill: var(--n5); } +.strip .st.f { fill: var(--red); } +.strip .st.on { stroke: var(--yellow-25); stroke-width: 3; } +.strip .st.dim { opacity: .3; } +.strip .cur { stroke: var(--n1); stroke-width: 1; } + +/* attempt */ +.figs { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 1px; margin: 4px 0 20px; border: 1px solid var(--shade4); border-radius: 4px; overflow: hidden; background: var(--shade4); } +.figs > div { display: grid; align-content: start; gap: 6px; min-width: 0; padding: 12px 14px; background: var(--shade6); } +.metric-label { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; min-height: 24px; } +.figs b { color: var(--n1); font: 600 20px/1.4 var(--sans); font-variant-numeric: tabular-nums; overflow-wrap: anywhere; } +.figs b.now { font: 500 14px/1.5 var(--sans); } +.figs b.now.warn { color: var(--yellow); } +.issue { margin: 0 0 20px; padding: 12px 14px; border-left: 2px solid var(--yellow); background: var(--yellow-10); } +.issue p { margin: 6px 0 0; color: var(--n2); } +.bigclimb { display: block; width: 100%; min-width: 1060px; height: auto; aspect-ratio: 1060 / 170; margin-bottom: 12px; } +.bigclimb text { font: 12px var(--mono); fill: var(--n4); } +.bigclimb .l { stroke: var(--green); stroke-width: 2; fill: none; stroke-linejoin: round; } +.bigclimb .a { fill: var(--green-10); } +.bigclimb .g { stroke: var(--shade4); } +.bigclimb .band { fill: var(--shade6); } +.bigclimb .ev { fill: var(--n1); } +.bigclimb .ev.first { fill: var(--shade7); stroke: var(--n3); stroke-width: 1.5; } +.bigclimb .ev.now { fill: var(--n1); } +.tabs { display: flex; gap: 2px; border-bottom: 1px solid var(--shade4); } +.tabs a { padding: 10px 12px; color: var(--n4); font: 500 13px var(--sans); border-bottom: 2px solid transparent; margin-bottom: -1px; text-decoration: none; } +.tabs a.on { color: var(--n1); border-bottom-color: var(--green); } +.tabs a i { color: var(--n4); font: 11.5px var(--mono); font-style: normal; margin-left: 6px; } +.checks { width: 100%; border-collapse: collapse; font-size: 13px; } +.checks th, .checks td { height: 34px; padding: 0 14px; text-align: left; border-bottom: 1px solid var(--shade4); white-space: nowrap; } +.checks thead th { color: var(--n4); font: 600 12px/1.4 var(--sans); height: 36px; } +.checks td.k { font-family: var(--mono); color: var(--n2); } +.checks td.d { color: var(--n3); white-space: normal; } +.checks td.h { color: var(--n4); font: 12px var(--mono); letter-spacing: .14em; } +.checks .h .p { color: var(--green); } +.checks .h .f { color: var(--red); } +.checks .h .x { color: var(--n4); } +.checks tr.group td { color: var(--n1); font-weight: 600; background: var(--shade6); } +.check-evidence { padding: 8px 0; min-width: 240px; } +.checks td:not(.d) { vertical-align: top; padding-top: 10px; } +.checks td.k { max-width: 180px; white-space: normal; overflow-wrap: anywhere; } +.check-evidence summary { cursor: pointer; } +.check-evidence summary:focus-visible { outline: 2px solid var(--n2); outline-offset: 3px; } +.check-evidence section { margin: 12px 0; padding-top: 12px; border-top: 1px solid var(--shade4); } +.check-evidence strong { font-size: 12px; } +.check-evidence p { margin: 8px 0; overflow-wrap: anywhere; } +.check-evidence pre { white-space: pre-wrap; overflow-wrap: anywhere; max-height: 240px; overflow: auto; font: 12px/1.5 var(--mono); } +.grade-key { flex-wrap: wrap; display: flex; gap: 18px; padding: 10px 14px; color: var(--n4); font: 12px/1.6 var(--sans); } +.grade-key .p { color: var(--green); } +.grade-key .f { color: var(--red); } +.grade-key .x { color: var(--n4); } +.shots { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 12px; padding: 14px 0; } +.shots button { padding: 0; border: 0; background: none; cursor: zoom-in; } +.shots img { width: 100%; border: 1px solid var(--shade4); border-radius: 4px; } +.lightbox { width: min(94vw, 1500px); max-height: 94vh; padding: 42px 12px 12px; border: 1px solid var(--shade1); border-radius: 4px; background: var(--shade8); } +.lightbox::backdrop { background: #000c; } +.lightbox form { position: absolute; top: 8px; right: 10px; } +.lightbox button { border: 0; background: none; color: var(--n2); cursor: pointer; } +.lightbox img { display: block; max-width: 100%; max-height: calc(94vh - 54px); margin: auto; } +.files-list { display: grid; gap: 6px; padding: 14px 0; } +.files-list a { color: var(--n2); font: 12px var(--mono); text-decoration: none; } +.log { margin: 14px 0 0; padding: 14px 16px; max-height: 520px; overflow: auto; background: var(--shade8); color: var(--n3); font: 12px/1.7 var(--mono); border-radius: 4px; } + +/* Local scrolling keeps labels readable without widening the page. */ +.crumbs, .title h2, .files-list a { overflow-wrap: anywhere; } +.sheet-scroll, .chart-scroll, .graph-scroll { max-width: 100%; overflow-x: auto; } +.chart-empty, .summary-note, .chart-caption { color: var(--n3); font: 12px/1.5 var(--sans); } +.chart-caption { margin: 0 0 16px; } +.graph-key { display: flex; flex-wrap: wrap; gap: 8px 18px; padding: 8px; font-size: 12px; } +.graph-key span { display: inline-flex; align-items: center; gap: 6px; } +.graph-key p { flex-basis: 100%; margin: 0; } +/* Secondary help stays out of the layout and above scrolling containers. */ +.metric-help { padding: 4px 0; border: 0; background: transparent; text-align: left; cursor: help; } +.metric-help:hover, .metric-help:focus-visible { color: var(--n1); } +.metric-tooltip { position: fixed; inset: auto; position-area: top span-right; position-try-fallbacks: flip-block, flip-inline; margin: 6px; width: min(260px, calc(100vw - 24px)); padding: 10px 12px; border: 1px solid var(--shade1); border-radius: 4px; background: var(--shade5); color: var(--n2); font: 12px/1.5 var(--sans); letter-spacing: normal; text-transform: none; overflow-wrap: anywhere; } +.btn:hover, .chip:hover, .nav a:hover, .tabs a:hover { color: var(--n1); background: var(--shade1); } +.btn.primary:hover { color: var(--n7); background: var(--green); filter: brightness(1.08); } +.btn:disabled { opacity: .55; cursor: not-allowed; } +.btn:disabled:hover { filter: none; } +@media (max-width: 900px) { + .topbar { height: auto; min-height: 48px; flex-wrap: wrap; padding: 10px 16px; gap: 12px; } + .tools { flex-wrap: wrap; margin-left: 0; } + .page { padding: 18px 16px 32px; } + .lane { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px; } + .lane-identity, .lane .phase { grid-column: 1 / -1; } + .figs { grid-template-columns: repeat(2, minmax(0, 1fr)); } + .title h2 { font-size: 22px; } + .tabs { flex-wrap: wrap; } + .sheet-scroll::before { content: 'Scroll horizontally to compare stacks'; display: block; padding: 6px 0; color: var(--n4); font-size: 12px; } +} +@media (max-width: 420px) { + .facts div { flex-basis: calc(50% - 1px); } + .page { padding-inline: 12px; } + .secret { flex-wrap: wrap; } + .secret input { max-width: 100%; } +} + +.feature-progress { margin-block: 28px; } +.section-heading { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 12px; } +.section-heading h3 { margin: 0; color: var(--n1); font-size: 15px; font-weight: 600; } +.section-heading nav { display: flex; gap: 6px; } + +.explore { position: relative; } +.explore summary { cursor: pointer; color: var(--n3); font-size: 12px; padding: 6px 0; } +.explore nav { position: absolute; right: 0; z-index: 2; padding: 10px; border: 1px solid var(--shade1); border-radius: 4px; background: var(--shade5); } +table.attempt-list { table-layout: fixed; min-width: 960px; } +table.attempt-list th:first-child { width: 16%; } +table.attempt-list th:nth-child(2) { width: 18%; } +table.attempt-list th:nth-child(3), table.attempt-list th:nth-child(4) { width: 10%; } +table.attempt-list th:nth-last-child(2) { width: 10%; } +table.attempt-list td { white-space: normal; overflow-wrap: anywhere; } +table.attempt-list .run-name { display: block; padding-block: 8px; color: var(--n1); text-decoration: none; } +table.attempt-list .run-effort { font-weight: 400; color: var(--n4); } +table.attempt-list .run-name:hover { text-decoration: underline; } +table.attempt-list .run-status { padding-block: 10px; } +.run-status summary { cursor: pointer; color: var(--yellow); } +.loading { display: flex; align-items: center; gap: 12px; min-height: 96px; color: var(--n2); font-size: 14px; } +.loading::before { content: ''; width: 16px; height: 16px; flex-shrink: 0; border: 2px solid var(--shade1); border-top-color: var(--n2); border-radius: 50%; animation: loading-spin .8s linear infinite; } +@keyframes loading-spin { to { transform: rotate(360deg); } } +main[aria-busy="true"]:not(:has(.loading))::before { content: ''; position: fixed; top: 0; left: 0; width: 30%; height: 2px; z-index: 10; background: var(--n2); animation: loading-progress 1.4s ease-in-out infinite; } +@keyframes loading-progress { from { transform: translateX(-100%); } to { transform: translateX(334%); } } +@media (prefers-reduced-motion: reduce) { main[aria-busy="true"]:not(:has(.loading))::before, .loading::before { animation: none; } } +[data-started-at] { font-variant-numeric: tabular-nums; white-space: nowrap; } +.time-grant { display: flex; flex-wrap: wrap; align-items: center; gap: .75rem; margin: 1rem 0; } +.time-grant label { display: flex; align-items: center; gap: .5rem; } +.time-grant input[type="number"] { width: 6rem; } + +.progress-heading { margin: 24px 0 8px; } +.progress-chart { display: block; width: 100%; min-width: 520px; max-height: 300px; } +.progress-chart text { fill: var(--n3); font: 12px var(--sans); } +.progress-grid { stroke: var(--n3); opacity: .15; } +.progress-panel { margin-bottom: 24px; } +.progress-controls { display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: 6px 8px; margin: 12px 0; } +.progress-stack { display: grid; grid-template-columns: subgrid; grid-column: 1 / -1; align-items: start; } +.chart-runs { display: flex; flex-wrap: wrap; gap: 4px; min-width: 0; } +.progress-controls .chart-stack-toggle { max-width: 12rem; overflow-wrap: anywhere; } +.progress-controls .chart-run-toggle { min-width: 7.5rem; font-variant-numeric: tabular-nums; } +.progress-controls button { display: inline-flex; align-items: center; gap: 6px; min-height: 32px; padding: 4px 8px; border: 1px solid transparent; border-radius: 4px; background: transparent; color: var(--n2); font: 12px var(--sans); cursor: pointer; } +.progress-controls button:hover { background: var(--shade1); } +.progress-controls button:focus-visible { outline: 2px solid var(--n2); outline-offset: 2px; } +.progress-controls button[aria-pressed="false"] { color: var(--n4); } +.progress-controls button[aria-pressed="false"] svg, .progress-controls button[aria-pressed="false"] .chart-swatch { opacity: .25; } +.progress-controls .chart-run-toggle[aria-pressed="true"] { border-color: var(--shade1); background: var(--shade5); } +.chart-swatch { flex-shrink: 0; } +.chart-run-toggle svg { flex-shrink: 0; } +.progress-series.is-muted { opacity: .15; } +.progress-series.is-highlighted .progress-line { stroke-width: 3; } +.distribution-run-label { display: none; pointer-events: none; paint-order: stroke; stroke: var(--shade8); stroke-width: 4px; } +.progress-series.is-highlighted .distribution-run-label { display: block; } + +.transcript-controls { margin-top: 16px; display: flex; flex-wrap: wrap; align-items: center; gap: 12px; margin-bottom: 12px; } +.transcript-controls label { min-width: 0; flex: 1; } +.transcript-controls select { max-width: 100%; width: min(100%, 560px); } +.transcript { max-height: 65vh; overflow: auto; overflow-anchor: none; border: 1px solid var(--shade4); border-radius: 4px; background: var(--shade8); padding: 16px; } +.transcript article, .transcript details { margin-bottom: 16px; } +.transcript pre { white-space: pre-wrap; overflow-wrap: anywhere; margin: 8px 0; font-size: 12px; line-height: 1.6; } +.transcript strong, .transcript summary { font-size: 12px; color: var(--n3); } + +.transcript-controls button { cursor: pointer; } +.transcript-controls button:hover { border-color: var(--green); } + +@media (max-width: 600px) { + .progress-chart { min-width: 640px; } + .progress-chart text { font-size: 16px; } +} + +.spend-pending { display: inline-block; width: 6px; height: 6px; vertical-align: middle; margin-left: 3px; } +.dot.a, .dag .d.a { animation: activity-pulse 2.8s ease-in-out infinite; } +@keyframes activity-pulse { 50% { opacity: .4; } } +@media (prefers-reduced-motion: reduce) { .dot.a, .dag .d.a { animation: none; } } + +.dag .passed-check { fill: none; stroke: var(--shade7); stroke-width: 1.2; } + +.chart-options { display: flex; flex-wrap: wrap; gap: 16px; align-items: center; } + +.chip[aria-disabled="true"] { opacity: .4; pointer-events: none; } + +.attempt-list tr.is-highlighted td, .chart-run-toggle.is-highlighted { background: var(--shade1); } + +/* Run setup uses native controls and one review step. */ +.setup{max-width:900px}.setup-form{display:grid;gap:24px}.setup-fields{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:16px}.setup label{display:flex;gap:8px}.setup-fields>label,.setup-actions>label{flex-direction:column}.setup label>span,.setup legend{color:var(--muted,#9eabb9);font-size:13px}.setup input:not([type=checkbox]),.setup select{min-width:0;background:#101c22;color:inherit;border:1px solid #29404b;border-radius:4px;padding:10px;font:inherit}.setup fieldset{border:1px solid #24383f;border-radius:5px;padding:16px}.setup-choices{display:flex;flex-wrap:wrap;gap:20px}.setup-model{display:flex;align-items:center;justify-content:space-between;gap:16px;padding:7px 0}.setup-model select{width:130px}.setup-actions{display:flex;align-items:end;justify-content:flex-end;gap:12px}.setup details>div{margin-top:16px}.setup-review{display:grid;grid-template-columns:160px 1fr;gap:14px}.setup-review dt{color:#9eabb9}.setup-review dd{margin:0}.setup .warning{border-left:3px solid #eabc65;padding:12px;background:#211e15}.setup pre{overflow:auto;max-height:260px}.setup .summary-note{margin:20px 0}@media(max-width:600px){.setup-fields{grid-template-columns:1fr}.setup-actions{align-items:stretch;flex-direction:column}.setup-review{grid-template-columns:1fr;gap:6px}.setup-review dd{margin-bottom:12px}} diff --git a/tools/stack-bench/dashboard/public/views/attempt.ts b/tools/stack-bench/dashboard/public/views/attempt.ts new file mode 100644 index 00000000000..7ebb647574a --- /dev/null +++ b/tools/stack-bench/dashboard/public/views/attempt.ts @@ -0,0 +1,207 @@ +import type { TranscriptPage } from '../../dashboard-transcript.js'; +// One attempt: figures, feature dependencies, and the evidence behind tabs. +// Each tab is a link, so what is open survives a reload and a back button. + +import type { AttemptCheck, AttemptChecks, AttemptPackage, CampaignProgression, CampaignSheet, SheetAttempt, SheetStack } + from '../../dashboard-views.js'; +import type { readCampaignTimeBudget } from '../../../src/campaigns/campaign-time-grant.js'; +import { graph } from '../graph.js'; +import { bigClimb } from '../climb.js'; +import { DASH, completionLabel, duration, executionClock, esc, metricLabel, spend, pct, phrase, ratio, stackLabel } from '../format.js'; + +export type AttemptTab = 'checks' | 'screenshots' | 'files' | 'log' | 'transcript'; + +export interface AttemptPageInput { + sheet: CampaignSheet; + progression?: CampaignProgression | null; + attemptId: string; + tab: AttemptTab; + checks: AttemptChecks | null; + evidence: AttemptPackage | null; + log: string; + transcript?: TranscriptPage | null; + timeBudget?: ReturnType | null; + canControl?: boolean; + controlError?: string; +} + +const GLYPH: Record = { pass: '', + fail: '', 'not-run': '·' }; + +function locate(sheet: CampaignSheet, attemptId: string): { + stack: SheetStack; + attempt: SheetAttempt; +} | null { + for (const stack of sheet.stacks) { + const attempt = stack.attempts.find(item => item.id === attemptId); + if (attempt) return { stack, attempt }; + } + return null; +} + +const CATEGORY = { feature: 'Feature', production: 'Production', interface: 'Interface', unknown: 'Unclassified' }; + +function checksTable(checks: AttemptChecks | null): string { + const errors = checks?.grades.filter(grade => grade.error).map(grade => + `

${esc(grade.id)}: ${esc(grade.error)}

`).join('') ?? ''; + if (!checks?.checks.length) return errors + '

No check results are recorded yet. Check the log for current work or an execution error.

'; + const features = new Map(); + for (const check of checks.checks) { + features.set(check.feature, [...features.get(check.feature) ?? [], check]); + } + const groups = [...features.entries()].map(([feature, items]) => { + return `${esc(feature)}` + + items.map(check => `${esc(check.id)}` + + `
` + + `${esc(check.description || check.id)}` + + check.observations.map((observation, index) => { + const grade = checks.grades[index]; + const label = `Grade ${index + 1}${grade?.level == null ? '' : ` · L${grade.level}`}`; + return `
${esc(label)} · ${esc(observation?.status ?? 'NO RESULT')}` + + (observation?.summary ? `

${esc(observation.summary)}

` : '') + + (observation?.expected != null ? `
Expected
${esc(observation.expected)}
` : '') + + (observation?.actual != null ? `
Observed
${esc(observation.actual)}
` : '') + + (!observation ? `

${esc(grade?.error ?? 'This check has no recorded result in this grade.')}

` + : observation.expected == null && observation.actual == null && !observation.summary + ? '

No observation details were recorded.

' : '') + + '
'; + }).join('') + '
' + + `${CATEGORY[check.category ?? 'unknown']}` + + `${check.history.map((outcome, index) => `${GLYPH[outcome] ?? GLYPH['not-run']}`).join('')}` + + '').join(''); + }).join(''); + return errors + '
Recorded grades, oldest first. Expand a check for evidence. ' + + '✓ Pass✕ Fail' + + '· No pass/fail result
' + + '
' + + `${groups}
CheckRequirementCategoryGrades
`; +} + +function artifacts(evidence: AttemptPackage | null, key: string, visual: boolean): string { + const items = (evidence?.executions ?? []).flatMap(execution => + visual ? execution.visuals : execution.artifacts.filter(item => item.kind !== 'visual')); + const link = (id: string): string => + `/api/campaigns/${encodeURIComponent(key)}/artifacts/${encodeURIComponent(id)}`; + if (!items.length) return `

No ${visual ? 'screenshots' : 'files'} are available for this attempt.

`; + if (visual) { + return `
${items.map(item => { + const source = link(item.id); + return ``; + }).join('')}
` + + '
'; + } + return `
${items.map(item => + `${esc(item.path)}`).join('')}
`; +} + +export function attemptPage({ sheet, attemptId, tab, checks, evidence, log, transcript, + progression, timeBudget, canControl = false, controlError = '' }: AttemptPageInput): string { + const found = locate(sheet, attemptId); + const crumbs = (tail: string): string => `
Campaigns / ` + + `${esc(sheet.title)} / ` + + `${esc(tail)}
`; + if (!found) { + return `
${crumbs(attemptId)}` + + '

Attempt not found

'; + } + const { stack, attempt } = found; + const clock = timeBudget?.observedAt + ? executionClock(new Date(Date.parse(timeBudget.observedAt) - timeBudget.consumedMs).toISOString(), + attempt.status === 'running' ? null : timeBudget.observedAt) + : executionClock(attempt.executionStartedAt, attempt.executionCompletedAt); + const latestGrant = timeBudget?.grants.slice().sort((a, b) => + a.request.requestedAt.localeCompare(b.request.requestedAt)).at(-1); + const pending = timeBudget?.grants.some(grant => grant.disposition === 'pending') ?? false; + const resumeWithTime = attempt.status !== 'running' && timeBudget?.continuation?.eligible === true; + const timeControls = canControl && timeBudget && (resumeWithTime || (attempt.status === 'running' && timeBudget.liveGrantSupported)) + ? `
` + + '' + + `` + + `Limit after request: ${duration((timeBudget.effectiveMinutes + 120) * 60)}` + + `${resumeWithTime ? 'Continues from the verified checkpoint.' : 'Keeps the agent running.'} Cost and repair limits stay fixed.
` + : canControl && attempt.status === 'running' && timeBudget?.liveGrantSupported === false + ? '

This controller does not support live time extensions.

' + : canControl && timeBudget?.continuation?.reason + ? `

Cannot resume: ${esc(timeBudget.continuation.reason)}

` : ''; + const grantStatus = latestGrant ? `

${esc( + latestGrant.disposition === 'pending' ? 'Time request pending. The limit has not changed yet.' + : latestGrant.disposition === 'accepted' ? `Time added. Limit: ${duration(timeBudget!.effectiveMinutes * 60)}.` + : `Time request rejected: ${latestGrant.reason ?? 'See the grant evidence.'}`)}

` : ''; + const name = `${stackLabel(stack.stack)} rep ${attempt.repetition}`; + const counts: Record = { + checks: checks ? String(checks.checks.length) : '', + screenshots: evidence + ? String(evidence.executions.reduce((total, item) => total + item.visuals.length, 0)) : '', + files: evidence ? String(evidence.executions.reduce((total, item) => + total + item.artifacts.filter(entry => entry.kind !== 'visual').length, 0)) : '', + transcript: attempt.status === 'running' ? 'live' : '', + log: attempt.status === 'running' ? 'live' : '', + }; + const tabs = (['checks', 'transcript', 'screenshots', 'files', 'log'] as const).map(entry => + `` + + `${entry[0]!.toUpperCase()}${entry.slice(1)}` + + `${counts[entry] ? `${esc(counts[entry])}` : ''}`).join(''); + const help: Record = { + 'Checks passed': 'Accepted checks passed / selected, including checks not reached.', + 'Weighted score': 'Earned points / available points.', + 'First build': 'First build at each level. Earlier fixes and feedback are retained.', + Repairs: 'Completed repairs / allowance. Per-feature limits apply.', + Elapsed: 'Consumed time across executions / effective time limit. Includes coding, grading, repairs, and host sleep. Time between executions is excluded.' + + (timeBudget ? ` Original limit: ${duration(timeBudget.originalMinutes * 60)}. Accepted extensions: ${timeBudget.extensionCount}.` : ''), + Time: 'Recorded attempt duration.', + Spend: 'Saved receipts or live usage at pinned prices. ~ estimate; ≤ upper bound.', + }; + const figure = (label: string, text: string, tone = ''): string => + `
${metricLabel(label, help[label])}
${text}
`; + const panel = tab === 'transcript' ? transcriptPanel(transcript) + : tab === 'checks' ? checksTable(checks) + : tab === 'log' ? (log ? `
${esc(log)}
` : '

No log output is recorded yet.

') + : artifacts(evidence, sheet.key, tab === 'screenshots'); + const issue = attempt.excluded + ? `
Why this run was excluded` + + `

${esc(attempt.excluded)}

` : ''; + const categories = Object.entries(attempt.checkCategories ?? {}).filter(([, value]) => value.selected > 0); + const categorySummary = categories.some(([category]) => category !== 'unknown') ? '
' + categories.map(([category, value]) => + figure(CATEGORY[category as keyof typeof CATEGORY], ratio(value.passed, value.selected))).join('') + '
' : ''; + const track = progression?.stacks.find(entry => entry.attemptId === attemptId); + const history = sheet.mode === 'dependency' + ? '

Feature dependencies

' + (progression && track + ? graph(progression, [{ stack: track.stack, + statuses: track.steps.at(-1)?.statuses ?? progression.nodes.map(() => 'locked') }]) + : '

Feature graph unavailable.

') + : `

Grade history

${bigClimb(attempt.climb, level => `L${level}`)}`; + return `
${crumbs(name)}` + + `

${esc(stackLabel(stack.stack))} ` + + `rep ${attempt.repetition}

` + + + `
${figure('Checks passed', completionLabel(attempt))}` + + figure('Spend', spend(attempt.spend, attempt.spendPending, attempt.liveSpend)) + + figure('Status', esc(phrase(attempt)), attempt.stalling ? 'now warn' : 'now') + + figure('Weighted score', pct(attempt.score)) + + figure('First build', pct(attempt.unaided)) + + figure('Repairs', ratio(attempt.repairs.used, attempt.repairs.budget)) + + figure('Elapsed', attempt.status === 'running' || attempt.executionCompletedAt + ? clock + + ` / ${duration((timeBudget?.effectiveMinutes ?? sheet.facts.timeLimitMinutes) * 60)}` : DASH) + + figure('Time', duration(attempt.timeSec)) + + `
${timeControls}${grantStatus}${controlError ? `` : ''}${issue}${history}` + + `
${tabs}
${tab === 'checks' ? categorySummary : ''}${panel}
`; +} + +function transcriptPanel(page?: TranscriptPage | null): string { + if (!page) return '
Loading transcript�
'; + if (!page.sessions.length) return '

No transcript is available for this run yet.

'; + return '
' + + (page.before === null ? '' : ``) + + '
' + + (page.skipped ? '

Some malformed transcript records could not be displayed.

' : '') + + '
' + + page.messages.map(message => message.tool + ? `
${esc(message.role)}
${esc(message.text)}
` + : `
${esc(message.role)}
${esc(message.text)}
`).join('') + + '
'; +} diff --git a/tools/stack-bench/dashboard/public/views/campaign.ts b/tools/stack-bench/dashboard/public/views/campaign.ts new file mode 100644 index 00000000000..439b881d672 --- /dev/null +++ b/tools/stack-bench/dashboard/public/views/campaign.ts @@ -0,0 +1,259 @@ +// Results compare stacks. Runs expose individual evidence. Feature views use +// the same selected attempt per stack, separate from aggregate results. + +import type { CampaignProgression, CampaignSheet, ProgressionStep, SheetAttempt, SheetStack } + from '../../dashboard-views.js'; +import { DASH, completionLabel, modelLabel, duration, executionClock, esc, metricLabel, spend, num, pct, phrase, ratio, stackLabel, statusWord } from '../format.js'; +import { progressChart } from '../progress-chart.js'; +import { graph } from '../graph.js'; + +export type QuestlineView = 'grid' | 'graph' | 'replay'; + +export interface CampaignPageInput { + sheet: CampaignSheet; + progression: CampaignProgression | null; + view: QuestlineView; + chart?: 'completion' | 'cost' | 'distribution'; + unit?: 'checks' | 'features'; + hiddenChartRuns?: ReadonlySet; + step: number; +} + +export interface ReplayEvent { + stack: string; + ordinal: number; + step: ProgressionStep; +} + +const DOT: Record = { passed: 'p', active: 'a', working: 'a', failed: 'f', + blocked: 'b', locked: 'o' }; + +function short(value: string | null): string { + return value ? value.slice(0, 12) : DASH; +} + +function latest(stack: SheetStack): SheetAttempt | null { + return stack.attempts.find(attempt => attempt.id === stack.selectedAttemptId) ?? null; +} + +function facts(sheet: CampaignSheet): string { + const fact = sheet.facts; + const dependency = sheet.mode === 'dependency'; + const depth = sheet.levels.length ? Math.max(...sheet.levels) : 0; + const cells: Array<[string, string, string]> = [['Mode', fact.mode, '']]; + const limits = fact.repairLimits; + const repairBudget = [ + limits.perFeature === undefined ? '' : `${limits.perFeature} per feature`, + limits.perDepth === undefined ? '' : `${limits.perDepth.count} per depth${limits.perDepth.carry ? " (carry forward)" : ""}`, + limits.total === undefined ? '' : `${limits.total} total`, + ].filter(Boolean).join(' · '); + cells.push(dependency ? ['Depth', String(depth), ''] + : ['Levels', sheet.levels.map(level => `L${level}`).join('–'), '']); + if (dependency) { + cells.push(['Work', fact.workSelection ?? DASH, ''], + ['Repair', fact.repairSelection ?? DASH, ''], + ['Repair budget', repairBudget || 'No count limit', 'Limits apply to each attempt. When limits overlap, the tightest remaining limit applies.']); + } else { + cells.push(['Repair budget', repairBudget || 'No count limit', 'Limits apply to each attempt.']); + } + cells.push(['Repetitions', String(sheet.repetitions), ''], + ['Agent', fact.agent ?? DASH, ''], ['Model', fact.model ?? DASH, ''], + ['Guidance', fact.guidance ?? DASH, ''], + ['Production quality', fact.productionQuality === null ? 'Mixed' + : fact.productionQuality ? 'Requested' : 'Not requested', 'Whether the prompt explicitly requests a production-quality app.'], + ['Recipe', [...new Set(fact.recipes.map(recipe => + [recipe.id, short(recipe.contentSha256)].filter(Boolean).join(' ')))].join(' · ') || DASH, ''], + ['Time limit', `${fact.timeLimitMinutes} min`, ''], + ['Spend limit', fact.spendLimitUsd === null ? DASH + : `$${fact.spendLimitUsd} per attempt`, ''], + ['Controller', short(fact.controllerImage), ''], ['Plan', short(fact.planSha256), '']); + if (sheet.mixedScope) cells.push(['Scope', 'mixed', 'attempts do not share one test plan']); + const continued = sheet.stacks.filter(stack => stack.continued).length; + if (continued) cells.push(['Continued', String(continued), '']); + + return `
${cells.map(([label, value, hover]) => + `
${esc(label)}` + + `${esc(value)}
`).join('')}
`; +} + +function questlineRows(sheet: CampaignSheet, stacks: readonly SheetStack[]): string { + const lead = stacks.find(stack => stack.questlines?.length)?.questlines ?? []; + const rows = lead.map(questline => { + const cells = stacks.map(stack => { + const owned = stack.questlines?.find(entry => entry.id === questline.id) ?? null; + const dots = (owned?.nodes ?? []).map(node => + ``).join(''); + const score = owned?.score ?? null; + return `
${dots}` + + `${pct(score)}
`; + }).join(''); + return `${esc(questline.title)}${cells}`; + }).join(''); + if (sheet.mode !== 'dependency') return ''; + return rows || `Feature progress appears after the first recorded grade.`; +} + +function levelRows(stacks: readonly SheetStack[]): string { + const levels = stacks.find(stack => stack.levels?.length)?.levels ?? []; + return levels.map(level => ['unaided', 'score'].map(kind => { + const cells = stacks.map(stack => { + const owned = stack.levels?.find(entry => entry.level === level.level) ?? null; + const points = kind === 'unaided' ? owned?.unaided ?? null : owned?.score ?? null; + return `
${points + ? ratio(points.score, points.max) : DASH}
`; + }).join(''); + return `L${level.level} ${kind === 'unaided' ? 'first build' : 'score'}${cells}`; + }).join('')).join(''); +} + +export function selectedProgression(progression: CampaignProgression, sheet: CampaignSheet): CampaignProgression { + return { ...progression, stacks: sheet.stacks.flatMap(stack => progression.stacks.filter(track => + stack.stack === track.stack && stack.selectedAttemptId === track.attemptId)) }; +} + +export function replayTimeline(progression: CampaignProgression): ReplayEvent[] { + const tracks = progression.stacks; + const depth = Math.max(0, ...tracks.map(track => track.steps.length)); + const events: ReplayEvent[] = []; + for (let ordinal = 0; ordinal < depth; ordinal += 1) { + for (const track of tracks) { + const step = track.steps[ordinal]; + if (step) events.push({ stack: track.stack, ordinal, step }); + } + } + return events; +} + +function marker(step: ProgressionStep, failed: boolean): string { + if (failed) return 'f'; + if (step.action === 'repair') return 'r'; + return step.action === 'grant' ? 'g' : 'b'; +} + +function replay(progression: CampaignProgression, cursor: number): string { + const events = replayTimeline(progression); + cursor = Math.min(Math.max(0, cursor), Math.max(0, events.length - 1)); + const span = Math.max(1, events.length - 1); + const selected = events[cursor] ?? events.at(-1) ?? null; + const failedAt = (step: ProgressionStep): boolean => step.targets.some(target => + step.statuses[progression.nodes.findIndex(node => node.id === target)] === 'failed'); + const title = (id: string): string => + progression.nodes.find(node => node.id === id)?.title ?? id; + const head = selected ? [['Step', ratio(cursor + 1, events.length)], + ['Stack', esc(stackLabel(selected.stack))], ['Action', esc(selected.step.action)], + ['Feature', selected.step.targets.length === 1 + ? esc(title(selected.step.targets[0] ?? '')) : `${selected.step.targets.length} features`], + ['Score', pct(selected.step.score)], ['Repairs', num(selected.step.repairs)]] + .map(([label, value]) => `
${label}` + + `${value}
`).join('') : ''; + // Drawn as one SVG per stack: the dashboard's policy allows no inline style, + // and a marker's position is geometry, not decoration. + const at = (index: number): number => 20 + 960 * index / span; + const rows = progression.stacks.map(track => { + const marks = events.map((event, index) => event.stack !== track.stack ? '' : + ``).join(''); + return `${esc(stackLabel(track.stack))}` + + '' + + `${marks}`; + }).join(''); + const snapshot = progression.stacks.map(track => { + const step = events.filter((event, index) => + event.stack === track.stack && index <= cursor).at(-1)?.step ?? null; + return { stack: track.stack, + statuses: step?.statuses ?? progression.nodes.map(() => 'locked') }; + }); + return `
${head}
` + + graph(progression, snapshot) + + `
${rows}
`; +} + +function board({ sheet, progression, view, step }: CampaignPageInput, + stacks: readonly SheetStack[]): string { + const chips = (['grid', 'graph', 'replay'] as const).map(entry => + `` + + `${entry[0]!.toUpperCase()}${entry.slice(1)}`).join(''); + const heading = stacks.map(stack => `${esc(stackLabel(stack.stack))}`).join(''); + const grid = (rows: string): string => `
${heading}${rows}
Feature
`; + let content: string; + if (sheet.mode !== 'dependency') content = grid(levelRows(stacks)); + else if (view === 'grid' || !progression) content = grid(questlineRows(sheet, stacks)); + else if (view === 'graph') { + const selected = selectedProgression(progression, sheet); + const snapshot = selected.stacks.map(track => ({ stack: track.stack, + statuses: track.steps.at(-1)?.statuses ?? selected.nodes.map(() => 'locked') })); + content = graph(selected, snapshot); + } else content = replay(selectedProgression(progression, sheet), step); + return '
' + + '

Feature progress

' + + (sheet.mode === 'dependency' ? `
Explore · ${esc(view)}
` : '') + + '
' + + content + '
'; +} + +export function campaignPage(input: CampaignPageInput): string { + const sheet = input.sheet; + const stacks = sheet.stacks; + const showRepairs = stacks.some(stack => stack.attempts.some(attempt => + attempt.repairs.budget > 0 || attempt.repairs.used > 0)); + const cell = (render: (stack: SheetStack) => string): string => + stacks.map(stack => `${render(stack)}`).join(''); + const help: Record = { + 'Checks passed': 'Median percentage of selected checks passed, across valid completed runs.', + 'Weighted score': 'Median score weighted by check points, across valid completed runs.', + 'First builds': 'Summed first-build points across levels. Earlier fixes and feedback are retained; this is not an unaided run.', + Regressions: 'Median count of previously passing checks that later failed, across valid completed runs.', + 'Valid runs': 'Completed runs with usable evidence; not necessarily all checks passed.', + Excluded: 'Invalid or incomplete evidence. Spend is retained in Total spend.', + 'Active time': 'Median measured-run time, excluding recorded provider waits and operator pauses. Run Elapsed shows wall time.', + 'Cost per valid run': 'Mean exact measured-run cost, including explicit resume history. Independent failed retries remain in Total spend.', + 'Total spend': 'All runs, including excluded. ~ estimate; ≤ upper bound. Pinned prices.', + }; + const row = (label: string, render: (stack: SheetStack) => string): string => + `${metricLabel(label, help[label])}${cell(render)}`; + const value = (text: string): string => `
${text}
`; + const heads = stacks.map(stack => { + const attempt = latest(stack); + const label = esc(stackLabel(stack.stack)); + return `${attempt + ? `` + + `${label}` : label}`; + }).join(''); + const repetitions = row('Valid runs', stack => value(ratio(stack.n, stack.attempts.length))) + + row('Excluded', stack => + value(num(stack.attempts.filter(attempt => attempt.excluded).length))); + return `
Campaigns / ` + + `${esc(sheet.key)}
` + + `

${esc(sheet.title)}

` + + `${sheet.provisional ? 'Provisional' : esc(statusWord(sheet.status))}
${facts(sheet)}` + + '

Results

' + + `
${heads}` + + row('Checks passed', stack => `
${pct(stack.completionRate === null ? null : 100 * stack.completionRate)}
`) + + row('Cost per valid run', stack => value(stack.costPerValidRun === null ? (stack.n ? 'Unknown' : 'Awaiting valid runs') : `$${stack.costPerValidRun.toFixed(2)}`)) + + row('Weighted score', stack => value(pct(stack.score))) + + (showRepairs ? row('First builds', stack => value(pct(stack.unaided))) : '') + + row('Regressions', stack => value(num(stack.regressions))) + + row('Active time', stack => value(duration(stack.timeSec))) + + repetitions + + row('Total spend', stack => value(spend(stack.spend, stack.spendPending, stack.liveSpend))) + + '
Metric
' + + (sheet.mode === 'dependency' ? progressChart(sheet, input.progression, input.chart, input.view, input.hiddenChartRuns, input.unit) : '') + + '

Runs

' + + `
${showRepairs ? '' : ''}` + + stacks.flatMap(stack => stack.attempts.map(attempt => { + const href = `/c/${encodeURIComponent(sheet.key)}/a/${encodeURIComponent(attempt.id)}`; + const effort = attempt.effort ? ` (${attempt.effort})` : ''; + return `` + + `` + + `` + + `` + + (showRepairs ? `` : '') + + `` + + ``; + })).join('') + + '
RunModelFeatures passedChecks passedSpendRepairsElapsedStatus
${esc(stackLabel(stack.stack))} ${attempt.repetition}${esc(modelLabel(attempt.model))}${esc(effort)}${completionLabel(attempt, attempt.featureCompletion ?? null)}${completionLabel(attempt)}${spend(attempt.spend, attempt.spendPending, attempt.liveSpend)}${ratio(attempt.repairs.used, attempt.repairs.budget)}${attempt.status === 'running' || attempt.executionCompletedAt ? executionClock(attempt.executionStartedAt, attempt.executionCompletedAt) : DASH}${attempt.excluded + ? `
Excluded · show reason

${esc(attempt.excluded)}

` + : esc(phrase(attempt))}
' + board(input, stacks) + '
'; +} diff --git a/tools/stack-bench/dashboard/public/views/campaigns.ts b/tools/stack-bench/dashboard/public/views/campaigns.ts new file mode 100644 index 00000000000..c07c1f03371 --- /dev/null +++ b/tools/stack-bench/dashboard/public/views/campaigns.ts @@ -0,0 +1,101 @@ +// Show every active attempt before the campaign history. + +import type { CampaignSheet, OverviewCampaign, OverviewEntry, SheetAttempt } + from '../../dashboard-views.js'; +import { DASH, esc, pct, phrase, shape, since, spend, stackLabel, statusWord } from '../format.js'; + +export type CampaignFilter = 'all' | 'attention' | 'completed' | 'ready'; + +const FILTERS: Array<{ id: CampaignFilter; label: string }> = [{ id: 'all', label: 'All' }, + { id: 'attention', label: 'Needs attention' }, { id: 'completed', label: 'Completed' }, + { id: 'ready', label: 'Ready' }]; + +function readable(campaign: OverviewEntry): campaign is OverviewCampaign { + return 'scores' in campaign; +} + +function matches(campaign: OverviewEntry, filter: CampaignFilter): boolean { + if (filter === 'all') return true; + if (filter === 'attention') { + return campaign.status === 'attention-required' || campaign.status === 'unreadable'; + } + if (filter === 'completed') return campaign.status === 'completed'; + return campaign.status === 'prepared'; +} + +function lane(sheet: CampaignSheet, stack: string, attempt: SheetAttempt): string { + const warn = attempt.stalling; + return `
` + + `` + + `
Completion` + + `${pct(attempt.completion?.rate == null ? null : 100 * attempt.completion.rate)}
` + + `
Cost` + + `${spend(attempt.spend, attempt.spendPending, attempt.liveSpend)}
` + + `${esc(phrase(attempt))}
`; +} + +function live(sheet: CampaignSheet): string { + const lanes = sheet.stacks.flatMap(owner => owner.attempts + .filter(item => item.status === 'running') + .map(attempt => lane(sheet, owner.stack, attempt))); + if (!lanes.length) return ''; + return `
${lanes.join('')}
`; +} + +function stackCell(campaign: OverviewEntry, stack: string, best: number | null): string { + const score = readable(campaign) ? campaign.scores[stack] ?? null : null; + if (score === null) return `${DASH}`; + const value = best !== null && score === best ? `${pct(score)}` : pct(score); + return `` + + `${value}`; +} + +function tone(status: string): string { + if (status === 'running') return 'run'; + if (status === 'completed') return 'done'; + if (status === 'attention-required' || status === 'unreadable') return 'warn'; + return 'idle'; +} + +function row(campaign: OverviewEntry, stacks: readonly string[]): string { + const summary = readable(campaign) ? campaign : null; + const best = summary && summary.status === 'completed' && !summary.provisional + ? stacks.reduce((top, stack) => { + const score = summary.scores[stack] ?? null; + return score !== null && (top === null || score > top) ? score : top; + }, null) : null; + return `` + + `${esc(campaign.title)}` + + `${summary + ? esc(shape(summary.mode, summary.levels, summary.repetitions)) : DASH}` + + `${esc(statusWord(campaign.status))}` + + stacks.map(stack => stackCell(campaign, stack, best)).join('') + + `${summary ? esc(since(summary.updatedAt)) : DASH}`; +} + +export function campaignsPage({ campaigns, sheets, filter, loading = false }: { + campaigns: readonly OverviewEntry[]; + sheets: readonly CampaignSheet[]; + filter: CampaignFilter; + loading?: boolean; +}): string { + const stacks = [...new Set([ + ...campaigns.flatMap(campaign => readable(campaign) ? Object.keys(campaign.scores) : []), + ...sheets.flatMap(sheet => sheet.stacks.map(entry => entry.stack)), + ])]; + const shown = campaigns.filter(campaign => matches(campaign, filter)); + const chips = FILTERS.map(entry => + `` + + `${entry.label}${loading ? '' : ` ${campaigns.filter(campaign => matches(campaign, entry.id)).length}`}`).join(''); + const body = loading ? `
Loading campaigns…
` + : shown.length ? shown.map(campaign => row(campaign, stacks)).join('') + : `No campaigns match this filter.`; + return `

Campaigns

${sheets.map(live).join('')}` + + `
${chips}
` + + '' + + stacks.map(stack => ``).join('') + + `${body}
CampaignScopeStatus${esc(stackLabel(stack))}Updated
`; +} diff --git a/tools/stack-bench/dashboard/public/views/plans.ts b/tools/stack-bench/dashboard/public/views/plans.ts new file mode 100644 index 00000000000..62b2296ec2a --- /dev/null +++ b/tools/stack-bench/dashboard/public/views/plans.ts @@ -0,0 +1,94 @@ +// Saved plan summaries and shared navigation. New runs use the setup page. + +import type { DashboardPlan } from '../../dashboard-model.js'; +import { DASH, duration, esc, money, num } from '../format.js'; + +export type Page = 'campaigns' | 'plans' | 'campaign'; + +export interface RunForm { + error: string; +} + +const HEADS: Array<[string, string]> = [['Plan', 'name'], ['Mode', 'shape'], ['Shape', 'shape'], + ['Stacks', 'stack'], ['Attempts', 'stack'], ['Parallel', 'stack'], ['Repairs', 'stack'], + ['Time limit', 'stack'], ['Attempt cap', 'stack'], ['Campaign cap', 'stack'], ['State', 'state']]; + +export function runName(planId: string, now: Date): string { + const pad = (value: number): string => String(value).padStart(2, '0'); + const stamp = `${now.getFullYear()}${pad(now.getMonth() + 1)}${pad(now.getDate())}` + + `-${pad(now.getHours())}${pad(now.getMinutes())}`; + return `${planId}-${stamp}`.toLowerCase().replace(/[^a-z0-9.-]+/g, '-') + .replace(/^[^a-z0-9]+/, '').slice(0, 120); +} + +export function topbar({ page, key, canStart, resumable, controllerOwner, error, reportFiles = [] }: { + page: Page; key: string; canStart: boolean; resumable: boolean; controllerOwner?: string | null; error: string; + reportFiles?: string[]; +}): string { + const artifact = (path: string): string => `/api/campaigns/${encodeURIComponent(key)}/artifacts/` + + btoa(path).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, ''); + const files = page === 'campaign' + ? '
Files
' + + `planstate` + + (reportFiles.includes('report/report.html') ? `report` : '') + + (reportFiles.includes('report/export-manifest.json') ? `export manifest` : '') + + '
' : ''; + const resume = resumable + ? '
' + + '' + + (error ? `${esc(error)}` : '') + '
' : ''; + const stop = canStart && controllerOwner + ? `
` + + '' + + (error ? `${esc(error)}` : '') + '
' : ''; + const nav = (on: boolean, label: string, href: string): string => + `${label}`; + return '
' + + 'STACK BENCH' + + `
${stop}${resume}${files}` + + `${canStart && page !== 'plans' ? 'Start a run' : ''}` + + '
'; +} + +function shapeOf(plan: DashboardPlan): string { + const levels = plan.levels ?? []; + if (!levels.length) return DASH; + const depth = Math.max(...levels); + if (plan.mode === 'dependency') return `depth ${depth}`; + return levels.length > 1 ? `L${Math.min(...levels)}–L${depth}` : `L${depth}`; +} + +function planRow(plan: DashboardPlan): string { + const budgets = plan.budgets ?? null; + const stacks = plan.stacks ?? []; + const cell = (value: string, hover = ''): string => + `${value}`; + return `` + + `${esc(plan.title)}` + + `${esc(plan.mode ?? DASH)}` + + `${esc(shapeOf(plan))}` + + cell(stacks.length ? num(stacks.length) : DASH, stacks.join(' · ')) + + cell(num(plan.attempts)) + cell(num(plan.parallelism)) + + cell(plan.repairBudget === undefined ? DASH : num(plan.repairBudget)) + + cell(budgets ? duration(budgets.attemptTimeoutMinutes * 60) : DASH) + + cell(budgets ? money(budgets.maxCostUsdPerAttempt) : DASH) + + cell(budgets?.maxCostUsdPerAttempt != null && plan.attempts != null + ? money(budgets.maxCostUsdPerAttempt * plan.attempts) : DASH, + 'Maximum across planned attempts; each attempt cap includes its retries') + + `${esc(plan.state)}`; +} + +export function plansPage({ plans, loading = false }: { + plans: readonly DashboardPlan[]; loading?: boolean; +}): string { + return `

Saved plans

` + + '

Plans record the exact configuration behind a run. Use New run to select its settings.

' + + '
' + + HEADS.map(([label, kind]) => ``).join('') + + `${loading + ? `` + : plans.length ? plans.map(planRow).join('') + : ``}
${label}
Loading plans…
No plans
`; +} diff --git a/tools/stack-bench/dashboard/public/views/run-setup.ts b/tools/stack-bench/dashboard/public/views/run-setup.ts new file mode 100644 index 00000000000..7007ad5658d --- /dev/null +++ b/tools/stack-bench/dashboard/public/views/run-setup.ts @@ -0,0 +1,122 @@ +import type { RunSetupCatalog, RunSetupRequest, RunSetupReview } from '../../../src/campaigns/run-setup.js'; +import { esc, money, modelLabel, stackLabel } from '../format.js'; +import { runName } from './plans.js'; + +const guidanceLabel = (id: string) => ({ neutral: 'Standard skills', + 'neutral-no-sdk': 'No SDK skills or dev workflow', + 'neutral-dev': 'Standard skills + dev workflow', + 'neutral-dev-no-sdk': 'Dev workflow without SDK skills' } as Record)[id] ?? id; + +export function initialRun(catalog: RunSetupCatalog, id?: string): RunSetupRequest | null { + const w = catalog.workloads.find(w => w.id === id) + ?? catalog.workloads.find(w => w.mode === 'dependency' && w.workSelection === 'progressive') + ?? catalog.workloads[0]; + if (!w) return null; + return { key: runName(w.track, new Date()) + '-' + crypto.randomUUID().slice(0, 8), + workload: w.id, workloadSha256: w.sha256, level: Math.max(...w.levels), stacks: [...w.stacks], + agents: [{ index: 0, effort: w.agents[0]!.effort ?? 'medium' }], + conditions: [(w.conditions.find(c => c.guidance === 'neutral-dev') + ?? w.conditions.find(c => c.guidance === 'neutral') ?? w.conditions[0])!.id], ...w.defaults, + productionQuality: true, maxCostUsd: w.defaults.maxCostUsd ?? 0, credentials: {} }; +} + +export function selectGuidance(conditions: RunSetupCatalog['workloads'][number]['conditions'], sdk: string, dev: string): string[] { + return conditions.filter(c => c.sdkSkills === (sdk === 'on') + && c.devWorkflow === (dev === 'on')).map(c => c.id); +} + +export function readRunForm(form: HTMLFormElement, catalog: RunSetupCatalog): RunSetupRequest { + const data = new FormData(form); + return { key: String(data.get('key')), workload: String(data.get('workload')), workloadSha256: String(data.get('workloadSha256')), + level: Number(data.get('level')), stacks: data.getAll('stack').map(String), + agents: data.getAll('agent').map(index => ({ index: Number(index), + effort: String(data.get(`effort-${index}`)) as RunSetupRequest['agents'][number]['effort'] })), + conditions: data.has('sdkSkills') ? selectGuidance(catalog.workloads.find(w => w.id === data.get('workload'))!.conditions, + String(data.get('sdkSkills')), String(data.get('devWorkflow'))) : data.getAll('condition').map(String), repetitions: Number(data.get('repetitions')), + productionQuality: data.has('productionQuality'), + parallelism: Number(data.get('parallelism')), repairs: Number(data.get('repairs')), + timeoutMinutes: Number(data.get('timeoutMinutes')), maxCostUsd: Number(data.get('maxCostUsd')), + pauseAfterDepth: data.get('pauseAfterDepth') ? Number(data.get('pauseAfterDepth')) : null, + credentials: { adapters: Object.fromEntries([...data].filter(([key, value]) => + key.startsWith('credential-') && value).map(([key, value]) => [key.slice(11), String(value)])) } }; +} + +export function runSetupPage(catalog: RunSetupCatalog | null, request: RunSetupRequest | null, + review: RunSetupReview | null, error: string, canStart: boolean): string { + const field = (label: string, input: string) => ``; + const option = (value: string | number, label: string, selected: boolean) => + ``; + const integer = (name: string, value: number, min = 1) => ``; + const alert = error ? `` : ''; + const head = '

New run

'; + if (!catalog) return head + '

Loading setup…

' + alert + '
'; + if (!request || !catalog.workloads.length) return head + '

No runnable workloads are configured. Run appliance setup to install the workload presets.

' + + catalog.errors.map(error => `

${esc(error)}

`).join('') + ''; + const w = catalog.workloads.find(w => w.id === request.workload)!; + const delivery = w.mode === 'dependency' + ? ({ progressive: 'Progressive dependency graph', feature: 'One ready feature at a time', + 'all-at-once': 'Full graph in one build' }[w.workSelection as string] ?? w.workSelection) + : 'Sequential levels'; + const splitGuidance = w.conditions.length === 4 + && new Set(w.conditions.map(c => `${c.sdkSkills}:${c.devWorkflow}`)).size === 4; + const guidanceChoice = (key: 'sdkSkills' | 'devWorkflow', label: string) => { + const value = w.conditions.find(c => request.conditions.includes(c.id))?.[key] ? 'on' : 'off'; + return field(label, ``); + }; + const model = (index: number) => w.agents[index]!; + if (review) { + const rows = [ + ['Workload', `${w.title} · L${request.level}`], + ['Work delivery', delivery], + ['Stacks', request.stacks.map(stackLabel).join(', ')], + ['Models', request.agents.map(a => `${modelLabel(model(a.index).model)} (${a.effort})`).join(', ')], + ['Guidance', request.conditions.map(id => guidanceLabel(w.conditions.find(c => c.id === id)!.guidance)).join(', ')], + ['Production-quality app', request.productionQuality ? 'Requested' : 'Not requested'], + ['Runs', `${review.attempts} attempts · ${request.repetitions} per combination · ${review.parallelism} concurrent`], + ['Repairs', `${request.repairs} per attempt`], + ['Limits', `${request.timeoutMinutes} minutes and ${money(request.maxCostUsd)} per attempt`], + ['Total cost cap', money(review.maxCostUsd)], + ['Pause', request.pauseAfterDepth ? `After L${request.pauseAfterDepth}` : 'None'], + ['Account', review.authentication.map(a => `${a.adapter}: ${a.profile ? `${a.profile.id} (${a.profile.mode})` : `appliance default (${a.source})`}`).join(', ')], + ]; + return head + '

Review run

' + rows.map(([key, value]) => + `
${esc(key!)}
${esc(value!)}
`).join('') + '
' + + (review.qualification === 'pending' ? '

Grading qualification is pending. Results will be provisional.

' : '') + + '

Cost caps use recorded token pricing. Subscription usage is not an invoice charge.

' + + `
Recorded pricing and runtime
${esc(JSON.stringify({ pricing: review.pricing, runtime: review.runtime }, null, 2))}
` + + `
` + + '
' + alert + ''; + } + return head + (canStart ? '' : '

This dashboard is read-only. Start the appliance to run a study.

') + + `
` + + '
' + + field('Workload', ``) + + field('Target', ``) + + `

${esc(String(delivery))}

` + + '
Stacks
' + + w.stacks.map(id => ``).join('') + + '
Models and reasoning' + + w.agents.map((agent, index) => `
` + + `
`).join('') + + '
App requirement' + + `` + + '

Build a production-quality application suitable for real users, not a prototype or demo.

' + + '
SpacetimeDB guidance' + + (splitGuidance ? '
' + guidanceChoice('sdkSkills', 'SDK skills') + + guidanceChoice('devWorkflow', 'Dev workflow') : '
' + w.conditions.map(c => ``).join('')) + + '
' + + field('Repetitions per combination', integer('repetitions', request.repetitions)) + + field('Concurrent attempts', integer('parallelism', request.parallelism)) + + field('Repairs per attempt', integer('repairs', request.repairs, 0)) + + field('Minutes per attempt', integer('timeoutMinutes', request.timeoutMinutes)) + + field('Cost cap per attempt (USD)', ``) + + field('Pause', `') + + '
Run name and accounts
' + + field('Run name', ``) + + [...new Set(w.agents.map(a => a.adapter))].map(adapter => field(esc(adapter), `')).join('') + + '
' + + '
' + alert + '
'; +} diff --git a/tools/stack-bench/docker-compose.yaml b/tools/stack-bench/docker-compose.yaml new file mode 100644 index 00000000000..7c3675d51ed --- /dev/null +++ b/tools/stack-bench/docker-compose.yaml @@ -0,0 +1,49 @@ +# Databases for the Postgres and MongoDB backends. +# +# Development-only ports, container names and volumes keep this stack separate +# from the appliance. The SpacetimeDB +# backend needs no service here; run `spacetime start` for it. +# +# docker compose -f tools/stack-bench/docker-compose.yaml up -d +# +name: stack-bench + +services: + postgres: + image: postgres:16@sha256:219341e4cedb06c8634f80af40851da3425b41b76603fd890272f58e37e139f7 + container_name: stack-bench-dev-postgres + ports: + - "127.0.0.1:6532:5432" + environment: + POSTGRES_USER: appuser + POSTGRES_PASSWORD: local-app-password + POSTGRES_DB: app + volumes: + - pgdata:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U appuser -d app"] + interval: 5s + timeout: 5s + retries: 12 + + # One local replica-set member exposes native transactions and change streams. + # This provides neither failover nor a multi-node availability test. + mongodb: + image: mongo:7@sha256:554a9bb1ec6e00c40ba078a41974a834d1a9a8ab1772645b69142afecc87f082 + command: ["mongod", "--replSet", "rs0", "--bind_ip_all"] + container_name: stack-bench-dev-mongodb + ports: + - "127.0.0.1:6537:27017" + volumes: + - mongodata:/data/db + healthcheck: + test: ["CMD", "mongosh", "--quiet", "--eval", "try { rs.status(); } catch (e) { if (e.code !== 94) throw e; rs.initiate({_id:'rs0',members:[{_id:0,host:'localhost:27017'}]}); } if (!db.hello().isWritablePrimary) quit(1)"] + interval: 5s + timeout: 5s + retries: 12 + +volumes: + pgdata: + name: stack-bench-dev-pgdata + mongodata: + name: stack-bench-dev-mongodata diff --git a/tools/stack-bench/docs/README.md b/tools/stack-bench/docs/README.md new file mode 100644 index 00000000000..5d242c54f24 --- /dev/null +++ b/tools/stack-bench/docs/README.md @@ -0,0 +1,53 @@ +# Stack Bench documentation + +Use the root [README](../README.md) for the product summary. + +## Run Stack Bench + +- [Development](development.md): local dependencies and source checks +- [Appliance operation](../appliance/README.md): configure and run campaigns +- [Execution jobs](execution-jobs.md): submit work, assign hosts, and integrate a task queue +- [Credential profiles](credential-profiles.md): select and attribute account/API-key use +- [Dashboard](../dashboard/README.md): optional web interface +- [Recovery](../appliance/RECOVERY.md): interrupted runs and retained resources +- [Release](../appliance/RELEASE.md): assemble and verify a release + +## Understand the system + +- [System design](system-design.md): ownership, data flow, and operator loop +- [Prompting method](prompting.md): prompt inputs, specification treatments, + stack guidance, and repair examples +- [Appliance design](../appliance/DESIGN.md): security and container boundaries +- [Grader](../grader/README.md): scoring, evidence, and grader validation +- [Reference apps](../reference-apps/README.md): grading fixtures and qualification requirements + +## Define benchmark work + +- [Authoring](authoring.md): add features, checks, prompts, and rules through their existing owners +- [Grading coverage](grading-coverage.md): current qualification gaps and check justifications +- [L4–L6 preparation](l4-l6-readiness.md): later-depth probe gaps and proposed production workloads +- [Research roadmap](research-roadmap.md): staged data collection, parallel runs, + comparison methods, and the research evidence pack +- [Ecommerce composition](../tracks/ecommerce/composition/README.md): packs, + recipes, calibration, and specification treatment +- [Ecommerce levels](../tracks/ecommerce/LEVELS.md): cumulative and dependency + progression +- [Chat levels](../tracks/chat/LEVELS.md): current chat scope + +## Visuals + +- [Dependency graph](dependency-graph.html): generated ecommerce feature graph +- [Technical guide](technical-guide.html): current run path +- [Presentation](stack-bench.html): product presentation and illustrative checks +- [How it works](how-it-works.html): isometric system map with a guided tour of a campaign and its qualification + +Qualification status belongs to the current definition and evidence, not these illustrations. +Use [Grading coverage](grading-coverage.md) for limits. A paused run requires its live +controller; controller-restart recovery of the pause is not supported. + +`dependency-graph.html` is generated from the current graph with +`npm run graph`. Do not edit it by hand. + +Markdown files under `backends/`, `conditions/`, `tracks/*/prompts`, and +`tracks/*/contracts` are executable benchmark inputs. They stay with their +owners and are not general documentation. diff --git a/tools/stack-bench/docs/audits/2026-09-12-probe-impact.md b/tools/stack-bench/docs/audits/2026-09-12-probe-impact.md new file mode 100644 index 00000000000..0883ac86863 --- /dev/null +++ b/tools/stack-bench/docs/audits/2026-09-12-probe-impact.md @@ -0,0 +1,212 @@ +# Probe fixes and campaign impact + +Campaign: `c12719bf8c915901d06b7ffc4903c1ada47c50953839bdb4cc38d489a4242e01`. +Audit date: 12 September 2026. No saved application or original result was changed. + +## Result + +Eight attempts produced an L3 grade with 109 checks each. SpacetimeDB 2 has no +completed L3 result and remains excluded from a full-run comparison. + +Of the **872 original final L3 check outcomes**: + +- **42 failures cannot establish the claimed production defect.** Each stopped on + a stale view or required a live update before the target could be measured. +- **48 passes need stronger checks.** The old probes can miss a defect. This is + not evidence that those applications contain the defect. +- **782 outcomes are outside these identified flaws.** This does not certify + every application behavior or qualify the full benchmark. + +| Attempt | Recorded pass count | Failures with a faulty observation path | Passes needing stronger checks | +|---|---:|---:|---:| +| SpacetimeDB 1 | 109/109 | 0 | 6 | +| SpacetimeDB 3 | 108/109 | 0 | 6 | +| MongoDB 1 | 88/109 | 7 | 6 | +| MongoDB 2 | 89/109 | 7 | 6 | +| MongoDB 3 | 88/109 | 7 | 6 | +| PostgreSQL 1 | 89/109 | 7 | 6 | +| PostgreSQL 2 | 87/109 | 7 | 6 | +| PostgreSQL 3 | 87/109 | 7 | 6 | + +These are check counts, not weighted points. The saved-app recheck below supplies +new measurements for the affected keys. It does not replace the original scores. + +## Which checks + +All six MongoDB/PostgreSQL attempts failed these observations in their final L3 grade: + +| Stable check key | Recorded failure | +|---|---| +| `ecommerce.spec.concurrency-safety.last-unit.201c` | Existing admin revenue stayed at zero. | +| `ecommerce.spec.access-control.purchase-session.101a` | Purchase stock setup used an old catalog view. | +| `ecommerce.spec.concurrency-safety.restock-race.202a` | Restock setup used an old stock view. | +| `ecommerce.returns-pricing.refund-accounting.203a` | Existing admin revenue stayed at zero. | +| `ecommerce.l3.deferred-durability.restart-survival.311a` | The ordinary restock prerequisite used an old stock view. | +| `ecommerce.l3.server-time.server-time.312a` | The final stock view did not receive the scheduled update. | +| `ecommerce.spec.transactional-integrity.books-balance.107a` | Existing admin revenue stayed at zero. | + +All eight completed attempts passed these six checks with weaker evidence: + +| Stable check key | Missing evidence | +|---|---| +| `ecommerce.operations-access.order-owner.204a` | Fresh owner state after a refused outsider cancellation. | +| `ecommerce.inventory-operations.warehouse-transfer.2a` | Selected-product stock in each warehouse. | +| `ecommerce.operations-access.operator-authorization.201a` | Selected-product stock in each warehouse after refusal. | +| `ecommerce.inventory-operations.stock-conservation.202a` | Selected-product stock in each warehouse. | +| `ecommerce.spec.transactional-integrity.stock-transfer-overdraw.2c` | Stored stock in each warehouse after overdraft refusal. | +| `ecommerce.spec.live-state.stock-transfers.2b` | Selected-product stock in addition to the displayed warehouse totals. | + +The wrong-product transfer weakness was reproduced with the real browser grader: +moving Desk Lamp stock instead of Espresso Machine stock satisfied the old aggregate +assertions. The new product-and-warehouse assertions reject that defect. + +The two SpacetimeDB restock timing passes remain supported. Their fresh early reads +occurred 74,269 ms and 74,318 ms after scheduling and showed unchanged stock. +Their later reads showed the exact increment at 120,263 ms and 120,081 ms. +The declared delay was 120,000 ms. A new elapsed-time guard protects slower future +restarts; its addition does not invalidate these observed timing results. + +## Earlier levels and the excluded attempt + +The artifact audit covered 1,376 check outcomes across all recorded levels: +81 at L1, 423 at L2, and 872 at L3. Repeated grades of a check on different saved +builds are separate observations. + +- Six L2 purchase-session failures have the same stale-view setup defect. +- SpacetimeDB 2 failed signout at L1 because the probe did not open its account menu. + Its L2 grade covered 23 checks instead of the 50 graded in the other attempts. + Its development path was therefore different. The process was later stopped + with an incomplete artifact. Keep this attempt excluded. +- Across all levels, 49 outcomes have an identified observation/contract error, + and 48 passes need stronger checks. No original record was deleted or rescored. + +## Changes + +- Product-specific warehouse assertions for transfer, overdraft, and access checks. +- Fresh reads for accounting, ownership, reservation, credit, and refund observations. + Dedicated live-update probes retain their live observers. +- Original-time anchors and early/late observations for deferred work. A missed + observation window is unmeasured, rather than an invented app failure. +- Separate return-button and direct pending-return checks, with a successful return + control and fresh stock/accounting observations. +- Reorder baselines, item/quantity checks, accepted purchases, and changed-value + access attempts. Automatic restock timing now has a defined product deadline. +- Recovery checks require an expired empty cart and renewed available-stock use. + Delivery notifications require a delivered order and no earlier matching notification. + +The new pending-return check and the later-level changes were not in this campaign's +selected L3 checks. They do not create extra historical failures or denominator entries. +The source definitions remain draft pending matching reference and defect-control +qualification. Focused checks do not supply that qualification. + +## Use of the data + +Keep the original scores, costs, source identities, and evidence. Withhold the full +campaign comparison as a verified result. The common subset outside the 13 affected +check IDs has 96 checks per completed attempt; any analysis of that subset must be +labelled as an audit-selected subset, not the original primary result. + +The affected measurements were rechecked on unchanged saved apps in separate diagnostic +artifacts. This tests the saved implementation. It cannot reconstruct development +work that a corrected earlier gate would have requested. A fresh run is required +for that full development-path comparison, including a replacement for SpacetimeDB 2. +No paid rerun was started for this audit. + +The counts come from each saved grade's `recipeRelease.checks` and criterion evidence, +not today's graph or dashboard labels. Local audit extracts are retained in +`local-notes/r5-check-evidence.json`, `r5-check-catalog.json`, `r5-impact.json`, and +`r5-restock-timing-audit.json`. They contain the per-attempt mapping behind this report. + +## Saved-app recheck + +All **104/104 selected check outcomes passed**: the 13 affected keys on each of +the eight completed L3 source snapshots. + +| Stack | Rep 1 | Rep 2 | Rep 3 | +|---|---:|---:|---:| +| SpacetimeDB | 13/13 | Excluded | 13/13 | +| MongoDB | 13/13 | 13/13 | 13/13 | +| PostgreSQL | 13/13 | 13/13 | 13/13 | + +This includes all 42 earlier failures with faulty observation paths and all 48 +passes that needed stronger probes. The other 14 observations repeat the seven +previously passing keys on SpacetimeDB 1 and 3. The revised checks found no defect +in this selected scope. This does not establish that the saved apps have no defects. + +All eight regrades used controller revision `486b8aa05` and the original build +image. Their receipts and grade bundles were audited for the original source and +run hashes, exact selected check keys, matching engine identities, bundle hashes, +completed cleanup, and absence of harness failures. The source remained unchanged. +There were **zero model calls** and no additional model cost. + +Do not discard the saved apps or buy new builds just to recover these measurements. +Keep this as a diagnostic result. A new campaign is needed to measure the complete +development path under the corrected grader; SpacetimeDB 2 still needs replacement. +No new paid run was started. + +Evidence is under the state volume's +`results/diagnostics/probe-regrade-486b//` directories. +Each contains `regrade.json` and `grading/bundle.json`. The consolidated receipt +audit is `results/diagnostics/probe-regrade-486b-audit.json`, with a local copy at +`local-notes/probe-regrade-audit.json`. + +## Control validation + +The selected checks were exercised against working references and deliberately +broken versions. Each baseline covered the 13 affected keys plus the two other +last-unit checks needed by the overselling controls. + +| Stack | Controller revision | Reference checks passed | Targeted defects caught | +|---|---|---:|---:| +| SpacetimeDB | `25e5c422b` | 15/15 | 12/12 | +| PostgreSQL | `486b8aa05` | 15/15 | 12/12 | +| MongoDB | `7a3304fc3` | 15/15 | 12/12 | + +The 36 defect results contain measured failures of their target checks. None has +a missing target, setup failure, harness failure, inconclusive result, or unrelated +failure. The recorded failures were inspected, not just the aggregate counts. +They cover incorrect stock and revenue, unauthorized actions, missing live updates, +and lost or mistimed scheduled work. Early execution was tested on SpacetimeDB; +the MongoDB and PostgreSQL timer defects prevent execution. + +Validation exposed and fixed four issues: + +- `25e5c422b`: the SpacetimeDB reference client omitted the restock quantity field + from its local TypeScript type. +- `7fd8b2523`: an optional navigation observation could exhaust its deadline and + throw a fatal scroll timeout. Required clicks and aborts still fail normally. + The focused browser-action tests passed. None of the 1,376 original outcomes + contains this failed scroll observation, so the historical impact counts do not change. +- `486b8aa05`: PostgreSQL reference startup reapplied its core schema and deleted + extension data, including scheduled work. Core schema setup now runs only for an + empty database. The live restart and timer controls pass. +- `7a3304fc3`: the MongoDB reference treated missing or foreign orders as input + errors. Cancellation and return now return 404 before changing stock or refunds. + The ownership control, server type check, and reference contract checks pass. + +Failed validation attempts remain separate evidence. No saved campaign app was +patched to obtain these results. Calibration inputs were refreshed without adding +qualification evidence. These are scoped, single-repetition diagnostics at the +listed revisions. The SpacetimeDB control predates the optional-navigation fix; +the two other stacks exercise that fix. This does not qualify a full current L3 release. + +Control artifacts are under the state volume's `results/diagnostics/` directory: +`probe-controls-25e5-r1-spacetime.json`, `probe-controls-486b-r1-postgres.json`, and +`probe-controls-7a33-r1-mongodb.json`. Each links its baseline, worker artifacts, +and individual defect evidence. `results/diagnostics/probe-controls-audit.json` +records the source identities and inspected failures, with a local copy at +`local-notes/probe-control-audit.json`. + +## Live-observation ordering review + +A follow-up review found that the new stored-stock reads preceded the live transfer +assertions. Slow database reads could therefore give the UI extra time. The reads +now follow both live assertions, preserving their original observation order and +waits. A focused contract check protects this ordering; scenario and calibration +validation pass. This edit does not promote qualification evidence from older revisions. + +The eight saved regrades already observed both live totals within 630–1,775 ms of +starting the transfer click. All were within 10 seconds, including the database-read +time. These passes did not depend on the extra time that the ordering could allow. +The action-timestamp audit is retained at +`results/diagnostics/probe-transfer-timing-audit.json`. diff --git a/tools/stack-bench/docs/audits/2026-09-12-review-implementation.md b/tools/stack-bench/docs/audits/2026-09-12-review-implementation.md new file mode 100644 index 00000000000..574179ed410 --- /dev/null +++ b/tools/stack-bench/docs/audits/2026-09-12-review-implementation.md @@ -0,0 +1,95 @@ +# Review implementation + +This change repairs measurement, runtime, and reporting defects. It does not qualify +the edited definitions or replace historical scores. No paid run is part of this change. + +## Measurement + +- Ordinary initial navigation timeouts use the same application-failure rule as + later navigation. Recognized browser and process faults remain harness failures. +- Conditional navigation reads the visible destination without waiting for animation + stability. An unreadable destination does not justify clicking a toggle blindly. +- Repair stall detection uses the best measured check outcomes in the existing event + history. First setup recovery counts as progress; repeating an earlier state does not. +- Return checks observe the contracted returned marker inside the matching order item. + They retain stock and refund assertions. Human-readable status text ignores case; + machine identifiers and protocol values remain exact. +- Production checks move from feature packs into specification packs. Ordinary + dependency prompts still omit specification requirements. Explicit specification + guidance remains a separate selection. The stock-transfer rejection check was + already selected once; its sequential category changes without removing points. +- Basic recommendation dismissal and persistence are separate checks. Refund/return + interaction remains requested product behavior, with one feature owner at L6. +- Delivery completion uses fresh views because the delivered modular request does + not require live delivery. Dedicated live-update checks keep their live observers. + +## Runtime and reporting + +- Each campaign must specify parallelism. Shared host admission is atomic and counts + each reserved execution index once. Temporary capacity shortages queue work; + impossible requests fail clearly. Admission does not rewrite the requested value. +- Controller and child use one claim timestamp. Supervisor errors remain in process + evidence, including when the child exits zero. An unexplained signal is not labelled + as an operator cancellation without matching intent. +- Corrupt job records do not stop unrelated dispatch or produce fabricated results. +- Broker budget stops retain measured spend and reservation details. They are provider + budget failures, not application defects. Account-mode reservations remain conservative + because the endpoint does not supply a verified enforceable per-request output cap. + Model and reasoning settings are unchanged. +- Comparison metrics use eligible attempts. Operational progress and incurred spend + remain visible. Live cost updates use the existing cache without full-state polling. +- Campaign reports omit absent receipt fields instead of serializing `undefined`. + Retained receipt values are validated before report aggregation. Reports and the + dashboard share one recorded-spend calculation. An incomplete execution keeps its + known subtotal while its final total remains unknown. + +## Historical use + +The [saved-app impact audit](2026-09-12-probe-impact.md) remains scoped evidence: +104 diagnostic rechecks across eight saved applications, not certified replacement +campaign scores. Original apps, requests, receipts, and results are preserved. + +| Historical case | Disposition | +|---|---| +| Eight completed L3 attempts in campaign `c12719bf…` | Keep original results and diagnostic regrades separate. The existing audit identifies 42 faulty failures and 48 weak passes; this change does not establish additional app defects. | +| SpacetimeDB 2 in that campaign | Exclude from a complete L3 comparison. The earlier signout probe changed its progression path; a final-app regrade cannot reconstruct that build. | +| Return 3c/3f, delivery 303a, refund interaction 757a/b, recommendation 504c | Later-depth scope. Do not add them to that historical L3 denominator. | +| Historical signal deaths | Retain interruption and known process evidence. Exit 143 alone does not identify the sender or invalidate all completed observations. | +| Broker-budget stops | Incomplete attempts, not completed application scores. Reserved money is not billed spend. | +| Dashboard aggregation defects | Recompute displays from eligible evidence; the display defect alone does not require paid reruns. | + +The subsequent read-only durable-record audit found 20 exit-143 executions in the +bounded inventory, rather than the review's 17. Their retained logs confirm SIGTERM +handling but not the sender. In `77c4e7`, the saved cancellation request occurred after +the six signal exits. In `24357e`, the frozen mode has no planned L2 pause. +Passed L2 snapshots therefore do not establish safe paused-run recovery. + +Eight allowance failures in `e373af` have $47.829793 in saved cost fields, all marked +incomplete. The PostgreSQL broker stop in `2e1193` has $1.449596 saved and occurred +before that job's later cancellation. These snapshot amounts are not reconciled final +spend or measured harness losses. The exact execution inventory is retained in the +local audit; no historical evidence was edited. + +## Qualification still required + +All edited calibrations remain draft with no earned qualification evidence. Matching +reference, null, and defect-control executions are separate release work. A successful +full-depth reference does not prove reachability on a lower-depth application. Staged +lower-depth states and pause/resume continuity need their own evidence when used. + +The pre-due observation bound remains unchanged: missing that window is inconclusive. +Fetch-based SSE streams are not supported by the current observer and fail closed; +they must not earn a privacy pass. Later-depth reference fixes need live qualification. +The new SpacetimeDB dismissal-loss control proves reconnect coverage, not backend +restart loss alone. Final-cent refund settlement has direct arithmetic coverage on +all three reference implementations; full reference app builds remain a separate check. + +## Implementation validation + +The combined build passed. The isolated dashboard suite passed all 67 checks. +The initial Linux unit and contract gate had 1,230 passes and 33 failures. Targeted +corrections resolved 32 failures; the remaining cost-report assertion was corrected +with the shared recorded-spend calculation. The final report, cost, checkpoint, +live-metric, and module-layout group passed all 50 checks. The full gate was not +repeated after those focused corrections. No paid campaign or live qualification +was launched for this implementation. diff --git a/tools/stack-bench/docs/authoring.md b/tools/stack-bench/docs/authoring.md new file mode 100644 index 00000000000..9990f2c9997 --- /dev/null +++ b/tools/stack-bench/docs/authoring.md @@ -0,0 +1,114 @@ +# Author a benchmark change + +Product text belongs in `tracks/`. Shared actions belong in `src/actions/`. Stack operations belong in `src/stacks/`. A normal feature or rule change does not need runtime, report, or dashboard edits. + +Build once with `npm run build`. The commands below then use the compiled tools. Keep before and after outputs outside the authored definition directories. Do not copy old hashes into new evidence. + +## Add a normal feature + +Use the existing customer profile as a worked example. Its complete path is: + +- `tracks/ecommerce/prompts/modular/customer-profile.md`: product request. +- `tracks/ecommerce/contracts/customer-profile.md`: stable application interface. +- `tracks/ecommerce/scenarios/progression-customer-profile.json`: observations and assertions. +- `tracks/ecommerce/composition/packs/progression-customer-profile.json`: feature, dependencies, and selected criteria. +- `tracks/ecommerce/composition/recipes/progression-catalog.json`: available packs. +- `tracks/ecommerce/progression/ecommerce.json`: graph ownership and dependencies. + +For a new delivery-note feature, follow that path with new IDs. Ask for “A customer can save and view a delivery note.” Use a text field, save button, and summary hook. Use existing `signUp`, `click`, `fill`, and `expect` actions. Put the sample note in the scenario, not the product request. Keep one positive criterion for saving and viewing the note. Do not award several points for several selectors that prove the same behavior. + +Create a feature pack with `moduleType: "feature"`. Declare its account dependency. Add the pack to the current recipe and give one graph node ownership of its grading group. Match the other graph nodes' `featureRefs`, `gradingGroups`, and `dependencies` format. Add the behavior to all reference stacks. + +```sh +node dist/commands/composition-cli.js pack validate tracks/ecommerce/composition/packs/progression-customer-profile.json --track ecommerce +node dist/commands/composition-cli.js recipe validate tracks/ecommerce/composition/recipes/progression-catalog.json --track ecommerce +node dist/commands/composition-cli.js recipe show tracks/ecommerce/composition/recipes/progression-catalog.json --track ecommerce +node dist/commands/check-scenarios.js --track ecommerce --recipe progression-catalog.json +node dist/commands/check-composition.js +``` + +The example commands validate the existing profile path. Substitute the new pack path for the first command. The recipe output records selected check IDs, task fragments, and identities. Review the task text for every stack and selected depth. The dependency prompt contract test covers fresh builds and repair text through all current depths: + +```sh +node --test dist/tests/dependency-neutral-prompt.contract.js +``` + +## Add an expected production check + +The profile scenario also shows the negative case: another customer must not see the saved address. For the delivery note, save a note as one customer, open a separate account, and prove the note is absent. Use independent actors. Do not let a prior criterion's pass be the only evidence for setup. + +Put the privacy criterion in a `moduleType: "specification"` pack with a product justification: private delivery instructions belong to their owner. Select it for scoring through the node's grading groups. The primary product request remains the normal feature request. A condition that explicitly supplies safeguards is a separate treatment. Do not add probe strings or negative-test instructions to general stack guidance. The intended SpacetimeDB skills remain enabled. + +Prefer an authoritative fresh read after a write or replay. A blocked button alone does not prove server authorization. A request timeout, status 0, missing route, or server error does not prove correct rejection. For a successful authenticated replay, prove that the stored effect occurred once. Unauthorized replay must still be refused. + +Add a mutant that exposes the other customer's note while keeping sign-up and saving functional. Declare the exact scenario and stable check ID. Run the existing anchor and syntax tests. Then obtain current baseline, null-control, and targeted mutation evidence before describing the new check as qualified. Static tests do not establish a mutation kill. + +## Match the observation to the claim + +- **Session persistence:** establish a session, reload, and observe the signed-in user without + `signIn`, `signUp`, or `ensureSignedIn` between the reload and the observation. +- **Reload persistence:** save data, reload, and observe it. Signing in again can isolate data + retention from session behavior. Browser storage survives reloads, so this alone does not + establish server persistence. +- **Hosted login refusal:** observe the provider's actual error, then use `reload` with + `application: true` to return to the trusted app URL in the same page. This preserves + app session storage. Check the app's signed-out state there. Once a protected operation + exists, probe it with `callAction` and `authentication: "optional"`: this sends any real + actor credentials, but permits a signed-out actor with none. Using `"none"` would discard + an illicit session and could hide an app that grants access despite provider refusal. + Prove the same operation works for an authorized actor and verify no unauthorized effect. +- **Server persistence:** use an independent client without copied application storage, or + suitable server evidence. Surviving a backend restart is a separate claim. +- **Restart survival:** first prove the saved state or ordinary scheduled operation works. + Restart the owned runtime without reseeding its data, then use a fresh client to verify + the result. Record which process restarted. A runtime-control failure is not an app + defect. This does not establish power-loss, storage corruption, or database crash recovery. +- **Shared live updates:** establish the observer's initial state, change data through another + actor, then observe without reload or re-navigation during the measured interval. Setup + reloads are valid. The initiating client's optimistic update is not sufficient evidence. +- **Autonomous execution:** closing clients is insufficient if the next request runs overdue + work. Use an observation that cannot trigger the work and a targeted negative control. + Otherwise state the narrower behavior measured. +- **Absence:** establish readiness first. `waitUntilAbsent` tests eventual disappearance; + `expect` with `absent: true` tests continued absence over its bounded `within` interval. + Neither establishes permanent absence. Same-actor observations can validly test deletion + or filtering; use an independent observer when the claim requires one. +- **Navigation:** reach the destination through disclosed controls. An optional control can + be absent; the required destination cannot. Do not assume a toggle is idempotent or require + a catalog round trip when the current view is already known. +- **Timing:** prefer completion signals. Keep elapsed-time waits when time is the behavior + under test. Explain unavoidable fixed waits in the scenario. Budget the full execution + path, including parallel branches, rather than only the longest individual wait. +- **Contention:** establish a successful serial operation, use independent actors, classify + every request, and reconcile stored state after the burst. A timeout is an unknown + business outcome until reconciled. Request overlap does not prove server execution + overlap or sustained capacity. A race mutation must preserve the serial operation. +- **Disclosure:** review the actual compiled request at the relevant step, including retained + contracts. Requested features may state timing or safeguards. Specification packs can + measure expected production behavior without requesting it. Disclose necessary interface + facts, but avoid layout restrictions and exact adversarial inputs. + +When a valid interface reveals a driver assumption, fix the shared action or the scenario's +entry sequence. Extend the closest executor test with the smallest alternate interface that +demonstrates the failure. Assert the destination or result so a no-op cannot pass. These +fixtures validate driver behavior; they do not qualify an application's business behavior. + +## Change a requirement or weight + +For a changed delivery-note length limit, edit the feature request, interface only if needed, and scenario assertions together. Keep the test input in the scenario. Preserve a stable ID only while the criterion still means the same thing. Give a materially different behavior a new ID and remove the retired selection. + +For a weight change, edit the criterion's `points` in its scenario. Check the compiled selection and graph score. Do not duplicate the weight in a report or UI. Check completion remains passed checks divided by the fixed selected check count; weighted score remains a separate measure. A zero-point control is excluded from scored check completion. + +Save `recipe show` output before and after the edit. Compare the selected checks, point totals, task fragments, and meaning/execution/content hashes. Use `recipe diff --track ecommerce` when comparing two authored recipes already in the track. Do not keep temporary duplicate IDs in the pack catalog. Re-run the matching scenario, composition, prompt, and mutation-definition checks. Regenerate the graph with `npm run graph` if the graph changed. + +## Add a study condition + +Copy the shape of `conditions/guidance/neutral.json`, choose a new ID, and register it in `conditions/catalog.json`. Change only the treatment you intend to compare. Preserve application interface selection and recorded skill identities. Select the condition in a campaign definition and compile the campaign with the existing campaign command. Do not add an agent-adapter branch for a guidance change. + +Declare repetitions, retry policy, budgets, and analysis before running. `analysis.spendThresholdsUsd` selects cost checkpoints; `analysis.completionTargets` selects target completion rates in `[0, 1]`. Reports use recorded grades only. Missing costs stay unknown and upper bounds remain marked. Cohorts retain stack, model, mode, level scope, skills, pricing, and definition identity, so a changed condition is not silently pooled with earlier results. + +## Review and qualification + +Check the rendered request and scoring scope separately. A prompt change, scenario change, reference fix, weight change, or runtime change makes evidence with the old identity stale. Current schemas derive qualification from identity-bound evidence; do not add retired `draft` or status fields to recipe or reference records. Pending qualification keeps scores provisional and blocks verified publication. It does not erase stored runs. + +Before release, require a baseline pass, a nonfunctional control, and a targeted failing mutant for the intended verified scope. Record fresh-build results separately from post-feedback repairs. Report blocked and unmeasured checks as part of the full scope. See [the current coverage review](grading-coverage.md) for known gaps. diff --git a/tools/stack-bench/docs/check-categories.md b/tools/stack-bench/docs/check-categories.md new file mode 100644 index 00000000000..5f83d9319f8 --- /dev/null +++ b/tools/stack-bench/docs/check-categories.md @@ -0,0 +1,27 @@ +# Check categories + +A category describes the property a criterion tests. It does not describe how the grader reaches the app. + +- **Feature:** a requested product operation or result, such as finding an item or creating a ticket. +- **Production:** an access boundary, ownership rule, consistency property, durability, concurrent correctness, deduplication, or synchronization property. +- **Interface:** presentation or a test hook without a separate product or production assertion. The reservation countdown is the current example. +- **Unknown:** the frozen definition does not contain category metadata. Old results keep this label. Current source must not classify historical results retroactively. + +Read counts from the frozen campaign's selected criteria, not from every criterion +in a scenario file. A depth-limited campaign selects only part of the graph. +Zero-point setup controls remain evidence but do not enter scored check completion. +The [compiled recipe](../tracks/ecommerce/composition/README.md#authoring-commands) +owns category and point metadata; this document does not maintain a second count. + +`category` is authored on the scenario criterion and copied into the compiled recipe and feature catalog. `role` stays separate. Roles control progression and prerequisites; categories only split reports. Neither point weights nor dependency gates change. + +A mixed criterion is production when passing it requires a production property. For example, a refund check that also tests duplicate refusal is production. This coarse label does not separate which assertion failed. Split such a criterion only through a reviewed definition change with new qualification evidence. + +Categories do not prove that a guarantee was supplied without being asked. That requires the separate [prompt disclosure audit](prompt-boundary-audit.md), including the exact delivered request, contracts, and selected skills. A production requirement can still be explicitly disclosed. + +Feature completion counts only fully passed dependency nodes. A node with passing feature checks but unfinished guarantees is not complete. Check completion counts accepted positive-point criteria. Both use the full selected target, including blocked and unmeasured work. + +The dashboard's Features/Checks choice changes the counting unit. It is not a +filter for the Feature category. A feature node can contain checks from several +categories. Weighted score is a third measure: passed points divided by selected +points. Keep all three denominators explicit in exported comparisons. diff --git a/tools/stack-bench/docs/credential-profiles.md b/tools/stack-bench/docs/credential-profiles.md new file mode 100644 index 00000000000..cc78d460b36 --- /dev/null +++ b/tools/stack-bench/docs/credential-profiles.md @@ -0,0 +1,53 @@ +# Named execution credentials + +A job selects credentials by profile ID. Selection order is attempt ID, adapter ID, +then default. Selection is explicit; the runner does not rotate accounts. + +Set `STACK_BENCH_CREDENTIAL_PROFILES_FILE` to an absolute path in trusted controller +storage. The file maps profile IDs to provider, mode, secret file, and version: + +```json +{ + "claude-work": { + "provider": "anthropic", + "mode": "subscription-token", + "secretFile": "/state/secrets/claude-work", + "version": "v1" + }, + "openai-api": { + "provider": "openai", + "mode": "api-key", + "secretFile": "/state/secrets/openai-api", + "version": "v1" + } +} +``` + +The example paths must be replaced with paths available inside the controller. +Use protected secret files. Do not put credential values in a job or campaign. + +Execution credential references have this form: + +```json +{ + "default": "claude-work", + "adapters": { "codex": "openai-api" }, + "attempts": { "an-exact-attempt-id": "claude-work" } +} +``` + +Profiles must match the selected adapter's provider. `anthropic` accepts API keys +or subscription tokens. `openai` accepts API keys or `subscription-token` mode; +that mode reads the existing Codex ChatGPT account login JSON file. `openrouter` +accepts API keys only. Normal provider preflight still validates authentication. + +Execution evidence stores only the profile ID, version, provider, and mode. +Secret contents and file paths are not attribution fields. Before each provider +invocation, the worker checks that its selected profile and secret have not changed +since admission. Update the profile version when deliberately replacing a secret. +Do not overwrite a secret used by an active attempt. Use a new profile for new work. + +Existing environment-based credentials continue to work when no named assignment +is selected. Profile selection clears conflicting credentials for that provider +and generic API-key overrides. It preserves other providers' credentials for +mixed-adapter jobs. diff --git a/tools/stack-bench/docs/dependency-graph.html b/tools/stack-bench/docs/dependency-graph.html new file mode 100644 index 00000000000..00b90aefcf1 --- /dev/null +++ b/tools/stack-bench/docs/dependency-graph.html @@ -0,0 +1,1377 @@ + + + + + +Stack Bench | Dependency Graph + + + +
+
+
+

Ecommerce dependency graph

+

Each row is a questline. Select a feature to see what it needs and what it unlocks.

+
+
+ +
+
+ Qualified feature pack + Draft feature pack +
+
+ +
+
+ +
+
+
+
+ + + + diff --git a/tools/stack-bench/docs/development.md b/tools/stack-bench/docs/development.md new file mode 100644 index 00000000000..bc18e260e8a --- /dev/null +++ b/tools/stack-bench/docs/development.md @@ -0,0 +1,286 @@ +# Stack Bench development + +This guide covers local source development. Use the +[appliance guide](../appliance/README.md) for runner configuration, credentials, +preflight, campaigns, and paid model work. + +## Requirements + +- Node.js 22 or newer +- Docker Engine with Compose v2 +- Chromium installed through the pinned Playwright dependency +- Linux for campaign and resource-lock tests; use a Docker development container + when the host is not Linux + +Install the locked dependencies and browser: + +```bash +cd tools/stack-bench +npm ci +npm run bootstrap:browsers +``` + +Build the local coding image: + +```bash +docker build --platform linux/amd64 -t stack-bench-build:local container +``` + +For real stack execution, use the [appliance build and setup](../appliance/README.md). +That build produces the CLI, server, and SDK from the branch. It needs no host +Rust build or ignored binaries. The appliance resolves local image tags to +immutable image IDs; published bundles use verified digest references. + +## Source checks + +Run the smallest check that covers the change: + +| Change | Check | +|---|---| +| TypeScript | `npm run typecheck` and the focused compiled test | +| Unit tests | `npm test` | +| Dashboard read model, routes, and pages | `npm run test:dashboard` | +| Repository contracts | `npm run test:contracts` | +| Mutation definitions and anchors | `npm run test:mutation-definitions` | +| Browser, process, and Docker integration | `npm run test:integration` | +| Prompt composition | `npm run check:prompts` | +| Track scenarios | `npm run check:scenarios` | +| Packs and recipes | `npm run check:composition` | +| Calibration | `npm run check:calibration` | +| Dependency graph | `npm run graph` | + +After a shared runtime, composition, grading, campaign, or release change is +stable, run the integrated source gate once: + +```bash +npm run lint +npm run typecheck +npm run test:all +``` + +Use `npm test` while changing code. Run `npm run test:dashboard` when the +dashboard read model, routes, or pages change; it writes thirty campaigns of +fixture evidence and stays out of the unit tier. Run `npm run test:contracts` +when tracks, prompts, reference applications, repository policies, or campaign +definitions change. `npm run test:all` runs the unit, dashboard, and contract +tiers after one build. Docker and qualification checks remain separate. +Campaign and lock tests exercise native Linux `flock`. A Windows host cannot +run those tests directly. Portable compiler and definition tests still run +locally. For a clean branch, the existing controller Dockerfile's `source` +target contains the source, development dependencies, and compiled tests: + +```sh +# From the repository root; this target does not build the Rust binaries. +docker build --platform linux/amd64 --target source -f tools/stack-bench/appliance/Controller.Dockerfile -t stack-bench-source-tests:local . +docker run --rm --init --network none stack-bench-source-tests:local npm run test:all +``` + +The release source build requires a clean normal Git clone. During development, +use a Linux container with the current edited checkout and locked dependencies. +Mutation-definition tests are model-free. Run them when reference source, grading +checks, or mutation manifests change. They do not run during ordinary unit work. + +Documentation-only changes need link and formatting checks, not the harness. +Run Docker checks only when the changed code affects their boundary. Run +targeted mutations while developing checks and the complete mutation set only +for a release candidate. Integration files run sequentially because they can +own browsers, processes, ports, and Docker resources. + +A passing check stays valid until one of its inputs changes. Do not rerun it for +reassurance. Add a test only when it protects a distinct invariant that an +existing test does not cover. Pending qualification marks campaign scores as +provisional; it blocks publishing verified comparisons, not campaign execution. + +For a pack with an unmeasured runtime budget, use `qualify-reference --timing-only` +to collect clean-reference timings before `pack-budget recommend`. This mode +cannot run mutations. Its artifacts are diagnostic and cannot qualify a release. +After setting the measured budget, run ordinary qualification on the frozen +candidate. Timing collection does not replace that gate. + +## Optional contention diagnostic + +`tracks/ecommerce/scenarios/diagnostic-checkout-contention.json` is a separate, +zero-point diagnostic. It does not run in scored campaigns. On a reset, +disposable reference app copy with its authenticated lease environment, use the existing +grader entry point: + +```sh +node dist/grader/grade.js --backend --app --url --level 2 --spec tracks/ecommerce/scenarios/diagnostic-checkout-contention.json --out +``` + +This standalone command deliberately omits `--track`. Both diagnostics include their named action mappings. Output is unbound to a recipe and has zero scored points; it cannot establish campaign completion. Backend reads still require the authenticated backend lease. + +This starts no coding agent. It changes application data, so do not point it at a +campaign app or its retained database. Prepare each stack with the same runtime +and resources. The probe requires the declared stock data interface and two +sessions of each fresh test account. It sends 1, 4, 16, and 64 parallel checkout +requests, with three fresh-account cohorts per width. These are request counts, +not distinct client counts or sustained throughput. + +The checkout diagnostic currently requires the verified reference schema. It does +not guess the schema of a generated app. Saved apps need a separate audited mapping. +Schema fingerprints are recorded with each stored-state observation. Unavailable +or malformed reads stay unmeasured, rather than becoming empty data or app failures. + +Each cohort records stored state before adding the item, after preparing the cart, +and after checkout. It requires one order with the correct owner, line quantities, +prices and warehouse allocations, one booked payment, the exact stock change, +and an empty cart with no remaining reservations. Existing orders and payments +must remain intact. PostgreSQL stores payment fields on the order; MongoDB and +SpacetimeDB use separate payment records. The shared assertion accepts either +stock reservation during cart preparation or stock consumption at checkout. +Rejecting all requests cannot pass. Retained action evidence contains each +request's timing, response status, and transport error or timeout. Timings cover +client dispatch through response, not server overlap or commit latency. Inspect +these observations separately from correctness. This draft diagnostic still +needs matching reference and targeted-defect qualification. + +Use `diagnostic-purchase-contention.json` with the same command to test competing +affordable purchases. It uses the declared `data-buy-input` interface and two +fresh customer accounts per cohort. Stock is reset to 128 in East and zero in +West before each cohort. Every request must be accepted, each account must show +its exact order count, and stored stock must decrease by the request count. +This diagnoses lost updates under bursts. It does not replace the separate +scarce-stock overselling check or measure sustainable throughput. + +The draft `diagnostic-checkout-application-crash.json` and +`diagnostic-checkout-database-crash.json` scenarios also have zero points and are +not selected by campaigns. They require a disposable, owned lease and a +`--restart-spec` with the backend, app path, port and probe. Select **one feature** +with `--feature` on freshly reset reference data for each trial. Do not run the +whole file on shared data: an earlier cart reservation can expire during a later +trial. SpacetimeDB uses only the database scenario because its application logic +and database share one process boundary. + +These probes kill owned processes with SIGKILL and restart them without resetting +storage. They record request outcomes, signal times and recovered business state. +Unconfirmed checkout effects may be absent or complete; partial effects and lost +confirmed state fail. SpacetimeDB calls use its native confirmed WebSocket protocol. +A separate checkout tests recovery progress. Application-crash recovery first +waits up to 70 seconds for the old database connections and transactions to end. +It records read-only observations and does not kill sessions or change timeouts. +If an HTTP call disconnects without proof that database work ended, stored-state +comparisons stay inconclusive until a fresh grade on reset data. A proven app +recovery failure still fails the recovery check when the crash window is valid. +A client timeout does not prove that server work stopped. Missed fault windows also remain +inconclusive. These are process-crash tests, not power-loss tests or proof of a +crash at a particular instruction inside a transaction. The diagnostics remain +draft and outside scored campaigns. + +Run independent diagnostic cases through the reference command inside the Linux +appliance. Set `STACK_BENCH_CONTROLLER_IMAGE_ID` and `STACK_BENCH_IMAGE` to immutable +image IDs. No model credentials or paid calls are needed. + +```sh +node dist/src/references/reference-live.js --diagnostic-plan /evidence/diagnostics.json --out /evidence/result.json +``` + +The plan selects existing zero-point scenarios and imported references: + +```json +{ + "schemaVersion": 1, + "groups": [{ + "backend": "postgres", "track": "ecommerce", "level": 3, + "recipe": "ecommerce.progression-catalog", + "scenario": "/workspace/tools/stack-bench/tracks/ecommerce/scenarios/diagnostic-checkout-database-crash.json", + "features": [9800, 9803], "repetitions": 10 + }] +} +``` + +Each feature gets its own leased worker, source copy, database and ports. The +worker builds once and resets data between repetitions. Host resource admission +controls startup. Use `--diagnostic-workers 1` for the same execution path in +serial, or set a per-command concurrency limit. There is no additional host cap. + +For a disposable candidate, add `source: { "path": "...", "sha256": "..." }`. +Its dependency files and deployment metadata must match the imported reference. +Declare exact criterion IDs in `expectedFailures` for defect controls. Source +paths and scenario paths are relative to the plan. Candidate source is copied; +the supplied tree is never edited. + +For an accepted saved L3 app, use `saved` instead of `source`: + +```json +{ + "run": "/evidence/attempt/run.json", "runSha256": "", + "checkpoint": 11, "source": "/evidence/accepted-source", + "reader": { "path": "/evidence/reader.json", "sha256": "" } +} +``` + +This path requires the final accepted checkpoint, its source and selection hashes, +and the original build image, run index, and database or module address. It installs +the app's own dependencies and does not deploy a reference app. Saved SpacetimeDB +apps require `STACK_BENCH_RELEASE_DEPS_VOLUME`, initialized from the original backend +image with the existing `appliance/dependency-volume` command. The runner verifies +the mounted SDK and native binaries against that backend image's manifest before +app startup. This volume supplies stack artifacts, not the app's `node_modules`. +Each trusted reader JSON contains `sourceSha256` and a reviewed mapping: + +- PostgreSQL: `sql` uses `:'account'` and `:'item'` in a read-only, repeatable-read transaction. +- MongoDB: `script` reads through `store` in an aborted snapshot transaction. It receives `account`, `item`, `key`, and `minor` helpers. +- SpacetimeDB: `tables` selects one native subscription snapshot; `convert(tables, account, item)` maps its rows. + +Each mapping returns `accountMatches`, `itemMatches`, and `state`. Both counts must +equal one. Reads require the owned container. Mapping programs are trusted operator +code, never supplied by the tested app. SpacetimeDB connection hooks can change +state before a fresh subscription; disclose this limit when the app has such hooks. + +Saved order-only state includes allocations and orphan counts. Map separate refund +records when present. Use `refundedMinor: null` when no order refund amount is stored. +These mappings cover selected accounting fields, not the entire database. They cannot +claim payment or reservation coverage. They support checkout and crash recovery; +direct-purchase histories and cancellation require separate qualified mappings. +Every new source needs a reviewed reader and deliberate defect controls before +running the audit. Saved-app failures are measured results, not expected-control +failures. All results remain zero-point diagnostics and leave prior scores intact. + +The output retains planned, started, collected, interrupted and unstarted trials. +Collected includes inconclusive results; it does not mean qualified. Raw grades +retain setup, action and assertion timing. Worker audits add deployment, reset, +grade and cleanup time. Unexpected failures stop new trials. Active trials finish; +explicit cancellation stops owned processes and releases their leases. +`--diagnostic-resume /evidence/previous.json` with a new output resumes only whole +groups that were never dispatched, under the same plan and images. Interrupted +executions stay visible and require an explicit new study to rerun. + +## Agent adapter contract + +Register an agent in `src/agents/agent-adapters.ts`. The existing registry accepts +a Node entry point; a new provider does not need another runner or result format. +Use `AgentRequest` from `src/agents/agent-adapter-contract.ts` and +`ValidatedAgentResult` from `src/agents/agent-result-contract.ts` as the protocol. +The runner sends arguments without a shell. The final non-empty stdout +line must contain one result JSON object. Earlier lines can contain logs. + +The request carries the selected model, mode, app directory, visible task and +guidance. Preserve them exactly. Do not expose grading definitions to the agent. +Declare the modes, credentials, network destinations and cost limits the adapter +actually supports. Registering an entry point requires rebuilding the release; +there is no runtime plugin loader. Adapter identities bind its entry-point bytes +and declared settings, including grading credentials. The release binds the +remaining source files. + +The runner validates results and deducts reported cost from the attempt's shared +budget. Unsupported cost limits fail before launch. A paid adapter must also use +the existing appliance, credential and cost-receipt controls; declaring a native +cost limit is not proof that an external scaffold enforces it. A standalone agent +has a deadline. An authenticated campaign delegates that deadline to its +supervisor so time grants remain effective. Cancellation stops the owned process +tree and group. Captured output is limited to 64 MiB per stream; exceeding that +limit rejects the result. + +`tests/agent-adapters.test.ts` sends a compiled visible task to an independent, +model-free entry point in all four modes. It checks exact delivery, shared budget +accounting and process cleanup. These tests qualify the protocol boundary, not a +new provider's billing integration or a complete install-to-run walkthrough. + +## Generated files + +Run `npm run graph` to rebuild `docs/dependency-graph.html` from the versioned +ecommerce graph. Do not edit generated output by hand. + +Build output, run artifacts, transcripts, local plans, and operational notes are +not product documentation and must remain untracked. diff --git a/tools/stack-bench/docs/execution-jobs-plan.md b/tools/stack-bench/docs/execution-jobs-plan.md new file mode 100644 index 00000000000..40949be7504 --- /dev/null +++ b/tools/stack-bench/docs/execution-jobs-plan.md @@ -0,0 +1,36 @@ +# Execution jobs + +The campaign fixes the experiment. A job assigns its execution policy and credentials. A worker runs the existing campaign engine. Secret values never belong in a campaign or job record. + +## Invariants + +- Preserve the full TypeScript server/client guidance selected by the campaign. +- Preserve requested parallelism. Resource waits must be visible; do not rewrite concurrency. +- Give each attempt only its selected credential. Record non-secret credential identity before execution. +- Use immutable submissions and exclusive claims. A lost worker is not permission to run a duplicate. +- Release resources only after verified cleanup. Keep host resource locks local. +- Preserve existing evidence readers and the running campaigns' frozen images. + +## Delivery sequence + +1. Add named credential profiles and per-attempt assignments using the existing provider adapters and credential broker. +2. Reserve only the dispatched attempt's stack resources. Release each reservation after verified cleanup. Support explicit wait/fail policy and cancellation. +3. Remove arbitrary repetition, initial-duration, and broker-request ceilings. Retain numerical, memory, request-size, cost, authentication, and isolation checks. +4. Add durable, idempotent job submission and a worker command. Snapshot the campaign input. Record the selected host and preserve a claim after worker loss. Reuse the existing atomic record writer and campaign runner. +5. Expose the same submission operation through the authenticated dashboard controls. External services can call the exported submission/worker functions or CLI without implementing campaign internals. +6. Verify synthetic credentials, duplicate submissions, competing workers, cancellation, resource reuse, failure ownership, and retained evidence. Run model-free integration before any paid execution. +7. Supply an opt-in local worker service that polls submitted jobs, uses explicit job concurrency, and drains on shutdown. Reuse the same job claim and runner. Keep per-campaign attempt parallelism unchanged. + +The first placement unit is a complete campaign on one worker host. Multiple hosts can claim different jobs. Splitting one campaign across hosts requires a separate distributed attempt coordinator and artifact-transfer contract; do not disguise filesystem locks as that coordinator. + +## Local worker status + +The seven steps above are implemented. The CLI, authenticated dashboard submission, and opt-in Compose worker use the same job store and campaign runner. Worker concurrency counts campaigns; it does not reduce a campaign's nine requested attempts. + +Synthetic tests cover exclusive claims, cancellation, retained failures, placement, concurrent campaigns, graceful drain, and independent named account secrets. They also check that a pre-claim error stops admission and drains active work without cancelling it or retrying the bad job. These tests do not prove shared provider quota enforcement or multi-host operation. + +The Linux model-free integration check starts the actual worker CLI in a separate process. It checks two jobs with nine active attempts each, cancels one job, drains the other on SIGTERM, and restarts the worker to dispatch a queued job. Completed evidence must stay unchanged. Run it after building with `node --test dist/tests/execution-jobs.integration.js`. It uses isolated temporary data and the stub backend; it does not verify native database cleanup, paid credentials, or the Compose deployment. + +Recovery remains explicit. A retained claim is not a lease that can expire. Inspect the campaign and reconcile its resources before further execution. Do not delete a claim or resubmit the same work to bypass uncertain paid execution. The surrounding service must authorize account access and manage shared account quotas; the local worker supplies neither automatic account rotation nor account-wide spend limits. + +An existing service queue and secret store should call this boundary directly. The standalone job store requires a filesystem that supports atomic hard links and rename. It is not an internet-facing authentication service. Shared account spending and provider request coordination belong at the credential service boundary, not in grading. diff --git a/tools/stack-bench/docs/execution-jobs.md b/tools/stack-bench/docs/execution-jobs.md new file mode 100644 index 00000000000..b8d24ad9639 --- /dev/null +++ b/tools/stack-bench/docs/execution-jobs.md @@ -0,0 +1,130 @@ +# Submit execution jobs + +A campaign describes a test. A job selects where and with which credentials to run it. +Each job runs one whole campaign on one host. Multiple workers can run different jobs +at the same time. The runner preserves the campaign's requested parallelism. + +## Submission + +Store the campaign manifest under the appliance results `plans/` directory. Use a frozen +plan for paid work. A draft is accepted only for a non-billable, model-free trial. +Configure [named credential profiles](credential-profiles.md) in trusted worker storage. + +Create a submission file: + +```json +{ + "key": "release-42-l2-repairs", + "planFile": "l2-repairs.json", + "credentials": { + "adapters": { "claude-code": "claude-work", "codex": "openai-api" } + }, + "hostId": "worker-east", + "capacityPolicy": "wait" +} +``` + +Only name adapters present in the plan. Credentials can also have a `default` and an +`attempts` map keyed by exact compiled attempt IDs. Attempt selections take precedence. +Omit `hostId` to let an eligible worker claim the job. This field restricts placement; +it is not host authentication. Omitting credentials retains the existing operator environment. + +Through the controller: + +```sh +job submit submission.json +job status +job list --limit 50 +job work --host worker-east +job cancel +``` + +For source development, use `node dist/commands/job-cli.js` before these arguments. +Set `STACK_BENCH_RESULTS_DIR` or pass `--results`. The normal appliance controller command +sets runtime image identity for `job work`. A worker must use the matching frozen controller +and coding images. Named secret paths must exist on that worker. + +Submission snapshots the plan. Repeating the same key and request returns the same job. +Reusing a key for different inputs fails. Submission does not start a model call. +`job work` claims and runs one job; an existing task queue can invoke that command on the +chosen worker. Credentials are resolved and pinned at attempt admission, not at submission. + +## API and service integration + +The existing local dashboard controls expose: + +- `POST /api/jobs`: submit the JSON above; returns 202 and the durable job status. +- `GET /api/jobs?limit=50&after=`: list one page. +- `GET /api/jobs/`: read status, assigned host, capacity wait, and campaign directory. +- `POST /api/jobs//cancel`: request cancellation. + +Writes require the same origin, browser token, and control-secret headers as existing +dashboard controls. This remains a local operator API. An authenticated product service +can instead call `submitExecutionJob` and `workExecutionJob` from +`src/campaigns/execution-jobs.ts`. Authenticate callers and authorize credential/profile +access before calling them. Scope idempotency keys by caller in that service. + +The job records contain references, not secret values or secret file paths. Per-execution +evidence records the admitted credential profile and version. Unexpected credential changes +fail before further provider calls. No automatic account rotation occurs. + +## Ownership, waiting, and recovery + +### Automatic local dispatch + +Run a worker to pick up queued jobs without invoking `job work` for each submission: + +```sh +job worker --host worker-east --concurrency 2 +``` + +Concurrency here counts **campaign jobs**, not attempts. Two jobs can each run nine +attempts. Each campaign retains its selected parallelism. There is no fixed job ceiling; +set concurrency to the work the host and selected provider accounts can support. +The worker checks host assignments and uses the same exclusive job claims as `job work`. +It polls the local job store once per second when idle. No second queue or dependency is used. + +The appliance provides an opt-in `worker` Compose profile. Set `STACK_BENCH_HOST_ID` +and `STACK_BENCH_JOB_CONCURRENCY`, then start the `worker` service with the normal setup +environment. Starting it authorizes execution of eligible queued jobs. Do not point an +experimental worker at a live queue. Use the controller image required by those plans. + +SIGTERM/SIGINT stops new claims and waits for active jobs. Use `job cancel` to stop a +specific campaign. Compose allows 24 hours for draining; override `stop_grace_period` +if admitted jobs can run longer. A forced kill retains claims and requires inspection. +A job failure stays recorded while the worker continues. A store or pre-claim error +stops admission and drains active work, so broken input does not enter a retry loop. + +This dispatcher is for the local appliance. At large backlog sizes, use the surrounding +product's durable queue to call `job work`; the local store scans directories. A production +multi-host deployment also needs shared credential quotas, a durable central job store, +and explicit evidence transfer. These are not supplied by the local dispatcher. + +Workers claim jobs with an atomic immutable record. A second worker cannot launch the +same job. Claims do not expire: a worker that loses contact may still have paid requests +in flight. A killed worker therefore leaves a retained claim for investigation rather than +an automatic duplicate. Use campaign status, stop, and authenticated reconciliation to +resolve owned resources. Failed jobs are not automatically retried by `job work`. +Reconciliation proves cleanup; it does not restore a live database or agent session. +See [interruption and recovery](../appliance/RECOVERY.md) before releasing retained work. + +The worker reserves only the actual stack resources for a dispatched attempt. It releases +them after verified cleanup. `capacityPolicy: "wait"` retains pending work and reports the +capacity wait; `"fail"` returns the resource error. Configuration and credential errors are +not retried as capacity waits. Cancellation reaches the runner and its cleanup path. + +Use the same local resource-lock root for all controllers targeting the same Docker host. +For separate hosts, those locks and runtime/work paths must be host-local. A shared job +store must support atomic hard links, rename, and durable writes, and all workers must see +the same job/result paths. Test these properties before using a remote filesystem. + +## Current boundaries + +- Placement is per campaign. One campaign's attempts are not distributed across hosts. +- This is not a replacement for the surrounding product's queue, authentication, or secret store. +- Shared provider quota and account-wide spend controls are not supplied by this job store. + Existing per-attempt money limits and staggered provider retries remain enforced. +- Full campaign state is still materialized. The compiler rejects work that cannot fit + numeric, array, serialization, or available heap limits before expansion. Removing the + old repetition ceiling does not make memory unlimited. +- No production multi-host throughput claim is made by the model-free local tests. diff --git a/tools/stack-bench/docs/grading-coverage.md b/tools/stack-bench/docs/grading-coverage.md new file mode 100644 index 00000000000..0156e50ec74 --- /dev/null +++ b/tools/stack-bench/docs/grading-coverage.md @@ -0,0 +1,367 @@ +# Grading coverage review + +## Purchase contention diagnostics + +The optional purchase, scarce-stock, and restock contention scenarios use the +existing request recorder and verified reference database readers. They compare +accepted purchases with each buyer's new orders and payments, preserve earlier +records, and reconcile stock against order allocations and restock requests. +Scarce stock limits accepted sales. Ample stock requires every purchase to succeed. +Mixed groups prepare credentials and inputs before dispatch and retain each result. +Unknown responses remain unmeasured. + +These are reference diagnostics, outside scored campaigns. They establish net +per-warehouse conservation and per-buyer counts. They do not identify each order +by a durable request ID, expose every compensating error, or prove intermediate +state correctness, server execution overlap, crash safety, or sustained throughput. +Saved model apps need verified reader mappings before these observations apply. + +## Concurrent cancellation diagnostic + +`diagnostic-cancellation-contention.json` sends overlapping cancellation calls +from two authenticated sessions of one account. It verifies the pending order +before dispatch, records every request outcome, then checks stored warehouse +allocations, cancelled status, preserved order/payment history and fresh revenue. +Repeated calls may refuse or succeed without additional effects. Unknown request +outcomes remain unmeasured; refusing all work or returning success without the +state change cannot pass. Request timings show client overlap, not server overlap. + +This diagnostic uses verified reference schemas and stays outside scored campaigns. +It covers non-credit orders. Payment-provider refunds, account-credit refunds, +other products' stock and arbitrary application schemas are outside its scope. +The diagnostic adds no feature points and does not change historical results. + +## Review failed checks + +The shipping-result check waits for the declared submission state to report success, then +verifies fresh staff and customer views. The state stays on the fulfilment panel when the +shipped row disappears. It does not require the queue or customer view to update live. The +separate live fulfilment check covers new orders appearing in an open queue. It does not +establish live removal after shipping or live customer-status updates. + +The separate shipping-accounting check uses the existing named shipping action with +staff credentials and the customer's declared order identifier. It waits for an accepted +server response before fresh order, stock, and revenue observations. This avoids a fixed +submission buffer in that production check; it does not test the shipping button. The +UI shipping check above still owns that interaction. Both changed scenarios are draft +pending matching live control evidence. The UI submission marker is app-reported evidence; +the fresh business observations still establish that shipping actually took effect. + +Support refund accounting now checks a second, unrefunded order after replay and fresh +login. This detects refunds applied beyond the selected order. The changed check is draft +until matching live reference and defect evidence exists. + +Return/refund checks at L6 exercise both operation orders. The product rule separates +stock receipt from money: accept the physical return once, restore stock once, and refund +only the amount still owed. Cumulative refunds cannot exceed the amount paid. The checks +read each warehouse, the refund total, and revenue. They remain draft pending matching live +controls. The new rule and checks do not apply retroactively to saved results. + +The low-stock live check keeps its observer on the open list while a separate signed-in +administrator restocks. It does not assume that entering the admin area resets its subtab. + +Application snapshots exclude `.log` and `.pid` files at every depth. This is a file-policy +boundary, not proof that each excluded file is disposable. Required source and seed inputs +must be retained in source files. Clean reconstruction must work without excluded runtime +files; source hashes alone cannot establish that. In-place restoration preserves runtime +logs, while a clean reset removes them. Use clean reconstruction for reproducibility claims. + +A failed check records an observation that did not meet an assertion. It does not identify an +independent bug or prove its root cause. Several checks can fail from one missing +update path or one failed setup step. + +For each investigated failure, keep a short review beside the retained evidence: + +- Identify the campaign, execution, source hash, stable check IDs, and grade files. +- Record the observed result separately from the proposed cause. Read the action + evidence and setup result before the final assertion. Link relevant traces, + logs, and source lines. +- State whether evidence confirms an application defect or a harness defect, or + whether the cause remains unresolved. Keep provider and interrupted outcomes + separate. A valid failed assertion can have an unresolved application cause; + an uncertain measurement cannot establish an application failure. +- Group checks only when evidence supports a shared cause. Keep every check's + recorded outcome and score. Do not report the group count as a measured bug count. +- State what evidence is still needed and which focused check can supply it. + +Keep claims within the measured boundary. A button shown to a guest proves a UI +visibility failure only when the contract forbids it. It does not prove the server +accepts a guest purchase. A missing stock number does not prove overselling. Use +direct-call results and stored quantities to assess those claims. Check whether +the supplied interface requires a number before blaming either app or grader for +an unreadable stock value. + +If review confirms a grader defect, preserve the original artifacts and explain +which comparisons are invalid. The automatic report reads artifact outcomes; a +review note does not change its classifications or scores. Fix the shared grader, +verify the affected behavior, and regrade the unchanged saved app into separate +evidence. Record the corrected grader identity and its relationship to the original +result. Do not present the original affected score as a valid comparison or count +the regrade as a new independent app build. No new model generation is needed. + +For dependency runs, a corrected gate can change which work the agent receives +next. A regrade can measure the saved application, but cannot reconstruct that +different development path. Keep it separate from new attempts under the corrected +definition. Show raw checkpoint checks beside accepted target completion and +blocked descendants; blocked checks are not independent observed failures. + +### Replay a saved dependency candidate + +Grading bundles include optional `phaseTimings` for application stop, database reset, +application start, readiness probes, and grader execution. Durations use a monotonic +clock and include failed operations. `suite: null` identifies preparation before +the scenario loop. `threw` records an exception, not whether a check passed; an +operation can return a failed result without throwing. The grader duration includes +its child process and evidence handling, so do not add it to the child grade duration. +The process log records final bundle writing and source verification separately. +These timings are diagnostics and do not change scores or timeout budgets. + +Use the existing `run` command with `--grade-from`, an explicit `--grade-level`, +one or more `--check` IDs, and a fresh `--out` directory outside the original +execution. The depth selects that depth's saved first-build candidate. It does +not select the final accepted app, which can be an earlier depth after rejection. + +```sh +node dist/commands/bench.js --grade-from /results/original/execution-1 \ + --grade-level 2 \ + --check ecommerce.spec.state-durability.session-reload.1e \ + --check ecommerce.spec.access-control.warehouse-write-boundary.103b \ + --out /results/diagnostics/session-and-authorization --no-media +``` + +Run this inside the configured Docker controller environment. The appliance +controller accepts the same arguments after `run`. No provider credentials or +model calls are required. The replay uses the original coding image, a fresh +owned backend and app directory, the saved credential aliases, and current checks. +It rebuilds the app from saved source; it does not restore old database contents. + +Independent diagnostic commands can run in parallel. Each claims its app ports +and backend resources through the same lease system as campaigns. There is no +manually sized runner pool. Admission reports resource conflicts. Use a separate +output directory for each command. Replays +keep their saved run index and server endpoint, so candidates that need the same +ports must run at different times. + +Also preserve the original generation dependencies. For example, regenerating +STDB bindings with a newer CLI can change their embedded version header and +correctly fail source verification. Set `STACK_BENCH_RELEASE_DEPS_VOLUME` to the +original release volume. Verify it with that release's immutable controller image +and `verify-deps`, mounted read-only. Then use Compose `run --no-deps` with the new +controller so its dependency initializer does not replace the old tooling. Keep +the new controller/backend identity in the diagnostic record; this is not a claim +that every runtime binary is identical to the original execution. + +The source run must have finished and must not be contaminated. The selected +depth must identify one saved first-build candidate with matching source and +grading evidence. Checks must belong to that candidate's original scored scope. +Missing evidence, changed source, ambiguous depths, and overlapping output paths +are errors. An inconclusive original measurement can be investigated; the replay +does not make that original result valid. + +Read `regrade.json` and its separate `grading/bundle.json`. The receipt identifies +the original run, source candidate, original grading evidence, current definition, +and cleanup result. It is diagnostic evidence, not a campaign run. Do not add its +checks or zero additional model cost as another trial in a stack comparison. + +Without `--grade-level`, the existing single-level sequential regrade retains its +original product-contract and scoring-scope checks. Dependency replay deliberately +permits current check definitions and records the difference. + +Scenario navigation must work with both separate pages and single-page views. +After reload, reopen a declared entry control when it exists, then require the +destination to be visible before inspecting its contents. An absence assertion +must not pass merely because the whole view is closed. Select account rows by +account identity, not text shared by their role options. Privacy checks must use +a refreshed positive control when live propagation has its own check. + +## Stock alert observation boundary + +The notification destination marker identifies the opened view, including while it loads. +Its aria-busy attribute is false only after the signed-in account's list loads successfully, +including an empty result. Loading or failed reads cannot earn empty-list credit. Entering +notifications must preserve an already-open destination; ordinary toggles may close it. +The initial alert request must report successful submission on its item card before the +first restock. Rejected or unconfirmed submission stops setup instead of becoming a missing +delivery failure. This replaces the fixed 2.5-second buffer. The marker is app-reported; +it does not independently prove a saved subscription. The later delivery check still verifies +the business effect. + +The duplicate-alert check samples a fresh client's loaded list after a ten-second wait following +the second restock. It checks one persisted alert at that observation point. It is not continuous +observation and does not exclude duplicates created later. The fresh client avoids relying on +an unchanged list in the initiating browser. A read that itself triggers overdue work can still +pass; this does not establish autonomous notification execution. Negative controls and live +reference evidence must match the changed scenario, interface, and reference identities. +The destination/readiness and submission-state markers are new interface requirements. +Preserve old runs under their original definition; do not count missing markers in a saved +application as agent failures. Changed marker scenarios remain draft until live references +and relevant defect controls match the new definition. + +## Qualification and source coverage + +### Stored state and contention + +Stock observations use the same item, warehouse, and stock interface already +required for external corrections. Reads use the authenticated backend lease. +Zero and negative quantities remain observations. Missing, invalid, or ambiguous +data cannot become a fabricated zero or a passing comparison. PostgreSQL resolves +the declared relational links; MongoDB and SpacetimeDB use their declared stock +interfaces. This does not provide an independent read of arbitrary application +tables, such as payments or orders. + +The restock race requires an ordinary stored restock in setup. Its scored check +then verifies stored stock, each buyer's order, and UI agreement. A failed setup +does not establish a concurrency defect. A stock assertion does not establish +that every other stored entity is correct. + +Named concurrent calls retain request timing and distinguish responses, transport +errors, and timeouts. A timeout has no known business outcome until state is +reconciled. Client request overlap is not proof of overlap inside the server. +The optional [contention diagnostic](development.md#optional-contention-diagnostic) +uses repeated request bursts. It is not a sustained capacity test or a change to +the scored campaign target. + +These changes are draft. Compilation, synthetic transport tests, and isolated +stock-reader checks do not replace live reference and targeted-defect evidence. +For a race control, preserve ordinary serial behavior and challenge the concurrent +case. For restart survival, preserve execution before restart. A disabled timer +only proves detection of absent execution, not restart-specific loss. The restart +probe first completes an identical ordinary timer. PostgreSQL and MongoDB controls +remove pending work at startup. The SpacetimeDB control keeps pending rows but loses +its process-local execution queue; isolate replacement can also lose that queue. + +The restock probe first verifies an ordinary purchase and restock. PostgreSQL and +MongoDB controls replace atomic reservation with an unlocked read and absolute +write. Fixed delays widen overlap in defect controls only; they do not measure a +natural failure rate. SpacetimeDB reducers remain atomic. Its control sends stale +absolute stock from the client, then overwrites intervening purchases. These are +distinct ways to break the same stock invariant, not equivalent internal races. + +Source coverage and executed controls are separate evidence. A declared mutation target is +not a successful control, and a failed setup is not a target kill. Historical inventory +counts do not establish the state of a changed definition. + +Use the current graph, recipe, reference registry, and mutation manifests as the source of +truth. The [mutation coverage checks](../tests/progression.mutation.ts) report missing exact +depth 1–3 targets. Source checks do not replace live controls. + +Current qualification is pending. Before a verified comparison, resolve material defects in +the selected scope and collect matching reference, null-control, and mutation evidence. +Keep missing definitions, unexecuted controls, failed or surviving controls, and stale evidence +separate. Record the exact source, engine, recipe, fixture, and result identities beside each +executed control. Do not copy old evidence into a changed calibration. + +An exploratory campaign can proceed with pending qualification, but its scores are +provisional. A gap outside its selected scope does not block it. A signed distribution and +its [release verification](../appliance/RELEASE.md) are separate from grading qualification. + +For each content finding, record the check and owner, material delivered at the relevant +step, observation and timing assumptions, a valid alternative implementation, control +evidence, and disposition. Review changed content and unresolved findings; do not repeat +an audit of unchanged material. Follow [authoring rules](authoring.md) when extending the +workload. Source inspection alone cannot qualify new depths or alternative interfaces. + +## Expected production criteria + +The current specification families have a product reason. They do not need a general request to “build production software.” Their scope must still follow the selected product features. These are semantic review findings, not a claim that live grading is qualified. + +| Specification family | Product reason and acceptance rule | +| --- | --- | +| `ecommerce.spec.state-durability` | Separate session continuity from saved data. Check cart, orders, profile, preferences, staff roles, and support history after runtime restart and fresh login. Retain reload checks for browser continuity. | +| `ecommerce.spec.access-control` | Customer data and staff operations have different owners. Test direct server calls as well as the visible interface. A refusal must have a defined result; transport failure is not proof. | +| `ecommerce.spec.live-state` | Shared catalog, inventory, cart, and operations views must reflect changes where the product calls for live information. Use distinct actors and bounded waits. Polling is acceptable when it meets the same observable rule. | +| `ecommerce.spec.concurrency-safety` | Several valid customers can act at once. Classify every request, allow stack-specific conflict results, and prove stock/cart/order invariants. Do not prescribe locks, reducers, or queue design. | +| `ecommerce.spec.external-data-sync` | A shared data view must not depend only on one client's local writes. Retain equivalent stack-specific mutation paths and fresh observations. | +| `ecommerce.spec.transactional-integrity` | Stock and money cannot be created or lost by partial operations. Prove the before/after quantities and totals, including rejected overdrafts. | +| `ecommerce.progression.cancellation-queue-specifications` | A cancelled order must leave the work queue. Keep queue visibility distinct from monetary accounting. | +| `ecommerce.progression.cancellation-accounting-specifications` | Cancellation must reverse only the appropriate stock and revenue effects. Repeat requests cannot reverse them twice. | +| `ecommerce.progression.price-accounting-specifications` | Current price edits must not rewrite earned revenue. Historical and future prices have different meanings. | +| `ecommerce.progression.price-history-specifications` | A buyer's receipt must keep the agreed purchase price. The scenario owns exact probe prices. | +| `ecommerce.progression.inventory-conservation-specifications` | A warehouse transfer changes location, not total inventory. Reject insufficient stock with no partial effect. | +| `ecommerce.progression.operations-access-specifications` | Administrative changes must follow product roles. A hidden button alone is insufficient. | +| `ecommerce.l3.deferred-access-specifications` | Scheduled work is still an authorized business operation. Schedule creation and execution cannot bypass access rules. | +| `ecommerce.l3.deferred-durability-specifications` | Reservations and scheduled restocks must survive the specified restart. Do not score a restart failure as an application assertion. | +| `ecommerce.l3.deferred-integrity-specifications` | Deferred work must produce one business effect. A replay can return success when stored state still proves one effect. | +| `ecommerce.l3.server-time-specifications` | Observe reservation expiry with its browser closed and scheduled work after restart. These probes do not change the host or client clock. They do not establish clock-skew tolerance. | +| `ecommerce.progression.review-access-specifications` | Review ownership and visibility follow the product's role rules. Exercise the direct access path and an independent observer. | + +Keep these rules. Keep the workload breadth and intended SpacetimeDB skills. Keep first-build measurements separate from post-feedback repairs. Do not call a score “production readiness”: these checks cover the declared product behaviors, not all security, accessibility, operational, or performance requirements of a deployed service. + +Concurrent requests need classified outcomes. Keep adversarial values in scenarios, not +product interfaces. For authenticated idempotent replay, verify unchanged totals and one +business record through a fresh authoritative read. Unauthorized replay remains a separate +refusal check. + +Review limits remain: static source inspection cannot prove timing thresholds are attainable on the Docker appliance, that all reference stacks pass, or that a mutant fails only its target. Those are release qualification gates. Current qualification remains pending. No weight changes or broad feature removals are justified by the present evidence alone. + +## September 2026 probe audit + +The source review covers all four ecommerce recipes, the full dependency graph through +depth five, both chat levels, and the separate contention diagnostics. Resolve depth from +the graph; a scenario's level field is not its dependency depth. Review selected criteria, +including their retained setup, rather than counting every criterion in a source file. + +The corrections reuse existing actors, actions, stock reads, and lifecycle controls: + +- Privacy observes scoped private data in responses as well as the page. Capture includes + HTML, JSON, text, native EventSource, and the existing WebSocket decoder. Positive owner + observations establish that the data was delivered. Dropped, unreadable, or unfinished + evidence cannot establish absence. Positive observations can wait for pending responses. +- Price, transfer, cancellation, and return checks prove the original business effect before + its preservation or reversal. Transfer races check each stored warehouse quantity as well + as the total. Authorized operations establish a working route before refusal checks. +- Cross-owner order checks combine the attacker's case with the other owner's order. + DOM parameter overrides preserve the caller's credentials and the adapter's wire types. +- Reorder, recommendation dismissal, notification privacy, and resync checks retain the + prerequisites needed when only that criterion is selected. Idempotent success is accepted + when fresh observations prove one business effect. +- Chat disappearance checks wait for the transition. Confidentiality checks retain a full + absence window. Room creation and room entry are separate actions. + +These changes follow the distinction between an interface check and a server authorization +check in the [OWASP authorization testing guide](https://owasp.org/www-project-web-security-testing-guide/v42/4-Web_Application_Security_Testing/05-Authorization_Testing/02-Testing_for_Bypassing_Authorization_Schema), +and its advice to verify business data in [integrity tests](https://owasp.org/www-project-web-security-testing-guide/v42/4-Web_Application_Security_Testing/10-Business_Logic_Testing/03-Test_Integrity_Checks). + +The supported claims remain finite: + +| Observation | Does not establish | +| --- | --- | +| Hosted app restart for PostgreSQL/MongoDB; SpacetimeDB runtime restart with retained data | Common database crash semantics, power-loss recovery, or corruption recovery | +| Checkout interrupted by an application or database process kill; recovered cart and orders reconciled with recorded requests | Power loss, disk corruption, every crash timing, or external payment durability | +| Private marker absent from supported captured responses | All endpoints, encodings, binary formats, or arbitrary object-reference attacks | +| Exact final stock, orders, and totals | Every intermediate state, general serializability, or an external payment ledger | +| Bounded concurrent requests | Sustained throughput, many independent users, or server execution overlap | +| Serial promotion redemption limit | Concurrent competition for the last redemption | +| Hidden return/activity controls and displayed activity fields | Server-side return authorization, audit-log confidentiality, or tamper evidence | + +Changed calibration inputs remain drafts with no imported qualification evidence. Runtime +budgets are planning ceilings; changed restart/observation allowances need fresh measurements. +Matching live references and defect controls are still required before a verified comparison. +Chat has additional qualification blockers recorded in [its level notes](../tracks/chat/LEVELS.md). +Passing source checks or an exploratory paid cohort does not remove these limits. + +Checkout crash integrity and acknowledged-order durability are two checks owned by +the checkout feature. PostgreSQL and MongoDB use separate application and database +process crashes. SpacetimeDB uses one combined process crash, with an explicit +shared observation for the application boundary. An uncertain outcome or a missed +fault window remains unmeasured. These checks require matching qualification; +older campaign scores are unchanged. + + +### Staff-role authorization follow-up + +Criterion 621b now requests a different role in both HTTP replay and reducer replay, +then reloads the administrator view to verify that a rejected request changed no role. +PostgreSQL and MongoDB have a denied-after-write defect control. SpacetimeDB reducer +rejection rolls back the transaction; its existing unauthorized-acceptance control +remains applicable. These changed checks have no matching live qualification evidence +and remain draft. + +Criterion 621d now checks administrator-role removal using the same signed-in staff +session before and after removal. The product policy grants administrator access to +`admin`, and staff access without administrator access to `staff` and `inventory`. +Reference role assignment updates the existing persisted administrator flag. The +probe proves a successful role change while authorized, then verifies denial and +unchanged stored role after administrator access is removed. Each stack has a +control that retains administrator access after removal. Matching live qualification +is pending; this check does not establish subscription revocation or token logout. diff --git a/tools/stack-bench/docs/how-it-works.html b/tools/stack-bench/docs/how-it-works.html new file mode 100644 index 00000000000..2216ae58feb --- /dev/null +++ b/tools/stack-bench/docs/how-it-works.html @@ -0,0 +1,826 @@ + + + + + + +Stack Bench · the proving ground + + + +
+ + STACK BENCH +
+
+

+ +
+ + + + diff --git a/tools/stack-bench/docs/l4-l6-readiness.md b/tools/stack-bench/docs/l4-l6-readiness.md new file mode 100644 index 00000000000..d79f590a124 --- /dev/null +++ b/tools/stack-bench/docs/l4-l6-readiness.md @@ -0,0 +1,151 @@ +# Dependency depths L4–L6 + +Implementation review: 2026-09-10, based on commit `90818215c` plus the current +working changes. This document is not qualification evidence. + +## Accepted scope + +Keep L1–L3 product work and dependencies unchanged. Keep returns at L5. Add six +features through the existing packs, contracts, scenarios, and reference apps. +Company accounts and purchasing approvals are not part of this change. + +| New feature | Depth | Product parents | +| --- | ---: | --- | +| Product bundles | 4 | Catalog management | +| Bundle checkout | 5 | Product bundles, reservations | +| Store credit | 5 | Payment records, staff roles | +| Subscriptions | 5 | Payment records | +| Bundle returns | 6 | Bundle checkout, returns | +| Split-tender refunds | 6 | Store credit, support refunds | + +| Depth | Previous features | Current features | +| --- | ---: | ---: | +| L1 | 4 | 4 | +| L2 | 10 | 10 | +| L3 | 13 | 13 | +| L4 | 9 | 10 | +| L5 | 6 | 9 | +| L6 | 1 | 3 | +| Total | 43 | 49 | + +The compiler derives depth from product dependencies. Check prerequisites can +require additional features without adding product edges. The generated +[dependency graph](dependency-graph.html) is the current graph view. + +L6 now covers cart recovery, bundle returns, and split-tender refunds. Equal node +counts would not imply equal difficulty or cost. Report reached, passed, failed, +and blocked work separately. Keep metric definitions fixed before collecting data. + +## Implemented measurement changes + +- Return completion uses an exact status. It first proves that the sale changed + stored stock and revenue, then checks restoration and a fresh customer view. +- Payment records require an exact paid status. The word “unpaid” cannot pass. +- Delivery notification checks wait for a loaded panel before testing absence. +- Bundle checks cover shared component stock, refused partial reservations, + expiry, saved component allocations, and direct authorization. +- Credit checks cover grant replay, unauthorized grants, one shared-cart checkout + race, and persisted credit after restart. +- Split refunds check exact original credit and external amounts, concurrent + refund requests, and persisted results after restart. +- Subscription checks cover scheduled order/payment counts, stock consumption, + restart, owner cancellation, and pause/resume across restart. + +The full catalog includes 21 checks added by these six features. Use the compiled +graph for current totals; later probe changes can add or reclassify checks. +Every added check has a declared defect target for all three stacks. + +These are executable definitions with reference implementations for each stack. +They are draft until matching positive and defect evidence passes. A compiled +scenario or passing source build does not establish live grading correctness. + +## MongoDB runtime + +Future MongoDB runs use a local single-node replica set, named `rs0`, with +application authentication and a private per-attempt database. This permits +multi-document transactions and change streams. It does not test replica failover +or multi-node availability. The MongoDB adapter version changes with this runtime. + +The running campaign retains its frozen standalone runtime. Do not pool its +results with the new configuration. Prior qualification evidence remains tied to +its original source and runtime identities. + +## Claim limits and remaining work + +- A shared-cart race is not a general wallet overdraft or throughput test. +- Local payment records do not prove correct external payment processing. +- Bundle scope excludes nested bundles and multiple reserved instances of the same + bundle in one cart. Remove and re-add a bundle to replace its reservation. +- A partial bundle return from a mixed-item order with credit or a discount is + refused. The reference offers a full support refund for that order. +- Subscriptions accept individual catalog items; bundles are excluded. +- The current subscription restart case does not establish recovery after a long + outage with many missed periods. Add that control before making the claim. +- The existing L4–L6 catalog still has unqualified checks and missing defect + controls. The review below is the remaining work list, not completed evidence. +- Preserve intentional TypeScript server, client, CLI, and dev guidance. Compare + the complete supplied stack package. Do not tune checks until a preferred stack + wins, or use its success rate alone to decide whether a workload is rigorous. +- Keep first-build, repair, and resumed results distinct. Later work can benefit + from prior repair feedback. It is not a new experiment from zero. + +## Completed focused checks + +- Native MongoDB authentication, transaction commit/rollback, process restart, + persisted data, database reset, and exact container cleanup passed. +- All three reference backends and clients compiled. Clean package installation + was corrected for the PostgreSQL and SpacetimeDB reference locks. +- Real credit checkout and refund actions passed on all three stacks: grant + replay, exact credit/external split, original-credit restoration, and no credit + increase after a repeated refund. +- Real scheduled deliveries produced the expected ordinary orders and payment + amounts on all three stacks. Runtime checks caught and corrected PostgreSQL + parameter typing and a stock-key query error; the failed transactions rolled back. +- MongoDB and PostgreSQL bundle smoke checks covered catalog writes, rejected + customer writes, component reservation, checkout, changed definitions, return + of the paid amount, and refusal of a repeated return. +- MongoDB and PostgreSQL recovery smoke checks aged only the scratch cart + timestamps, then changed the bundle definition. Recovery preserved the original + price and component quantities. This is not a real five-minute timing run. + SpacetimeDB recovery passed schema generation and type checking. +- Scenario validation and full-depth prompt-boundary checks passed. Mutation + anchors and syntax were checked, but the new defect controls were not executed. + +Declared controls include lost credit and pending work, but they have not been +executed. They do not yet establish restart qualification for the new checks. The subscription smoke verifies ordinary execution; +its restart, cancellation, and pause probes still require live qualification. + +## Validation sequence + +1. Validate graph, selected contracts, scenarios, reference builds, and mutation anchors. +2. Run focused model-free behavior checks for the changed money and timer paths. +3. Qualify changed scopes with correct references and targeted defect controls. +4. Freeze matching source, runtime, definitions, and evidence before comparing a new cohort. + +No new paid campaign or full qualification run is part of this implementation. +Current evidence must not be relabeled after definitions or reference sources change. + +## Review of every later feature + +These are source findings from the baseline and proposed checks. The exact-status, +stored return accounting, and notification-readiness fixes above are now implemented. A proposed race or restart case +still needs a valid reference and a defect control before it supports a claim. + +| Depth / feature | Current evidence or gap | Preparation | +| --- | --- | --- | +| L4 Price history | Checks live prices, paid-price preservation, revenue, direct authorization, and cart checkout. | Add a price-change/checkout race. Accept a consistent permitted price; reject mixed order, payment, and revenue totals. State the price policy before grading. | +| L4 Reservations | Checks holds, expiry, renewal, checkout, and restart. Most stock assertions read the UI. | Reuse stored stock reads. Race checkout against expiry and renewal against the old timer. Check that a sale or release occurs once and a renewed hold is not released by stale work. | +| L4 Order delivery | Checks eventual delivery and one displayed completed order after restart. | Check the allowed transition history and side effects. A single final row cannot prove one execution. Add cancellation/shipping conflict cases and restart while work is pending. | +| L4 Payment records | Concurrent checkout produces one order, one displayed payment record, and an exact amount in a fresh client. | Use exact payment status, durable amount/count observations, and replay after lost acknowledgement. Local records alone do not prove correct external charging. | +| L4 Promotion checkout | Checks one displayed discount and sequential expired/exhausted-code errors. | Race buyers for the final redemption. Inspect persisted orders, discount totals, and usage count. Show that invalid codes cannot change server totals, even through direct checkout. | +| L4 Personalized recommendations | Checks specific ordering and separation of customers' lists. | Add fresh-login persistence and direct ownership checks where account data is exposed. Keep the stated ranking policy; do not grade subjective recommendation quality. | +| L4 Staff activity | Checks one visible actor/action/subject/time entry. Customer access is tested by an absent link. | Test direct reads, persisted history, and actor attribution after role changes. Require a valid timestamp, not just a time element. Test multiple action types before claiming all changes are audited. | +| L4 Order-linked support | Includes a valid owner action, forged other-owner order linkage, refusal, and a fresh view. | Also test another customer's case ID, direct order reads, and persistence. Keep case ownership and order ownership separate. | +| L4 Automatic reorder | Counts one pending row after sequential sales; tests unauthorized rule replay. | Verify the row's item, quantity, destination, and eventual stock effect. Race threshold crossings, restart pending work, and prove the next threshold cycle can schedule again. | +| L5 Returns | Checks stock/revenue returning to baseline and return-button absence before shipping. | First prove the original sale changed stock and revenue. Require exact returned status, a direct premature-return refusal, owner checks, and duplicate/concurrent return accounting. | +| L5 Cart expiration | Waits for expiry, stock release, and an empty cart; includes restart. | Distinguish the 90-second reservation from five-minute cart inactivity. Specify which actions reset inactivity. Test activity near expiry and prevent a stale timer from deleting an updated cart. | +| L5 Promotion reporting | Checks one redemption and one discounted revenue value. | Reconcile several orders and promotions after replay and restart. State whether reports show gross sales or net refunds; do not assume a refund accounting policy. | +| L5 Delivery notifications | Counts one owner notification and no matching notification for another customer. | Require a loaded destination for empty-list assertions. Check disabled preferences, restart, repeated delivery, and persisted count. Do not infer autonomous delivery from a read that may trigger work. | +| L5 Recommendation feedback | Tests dismissal after restart and another customer's unchanged list. | Verify successful list loading and an unrelated positive result before absence. Add direct cross-account mutation and a fresh other-account view. | +| L5 Support refunds | Checks amount, one refund record after serial replay, and customer refusal. | Race two staff refunds and a refund against a return. Prove aggregate refund cannot exceed paid amount. Check order, case, payment, and inventory effects after restart; first specify refund versus restock policy. | +| L6 Cart recovery | Checks restored cart rows and warning text after a five-minute wait. | Prove exact quantities and stored stock deltas. Race two restores and a competing purchase. Replay after restart; test ownership. Partial recovery must preserve available lines without reserving unavailable units. | diff --git a/tools/stack-bench/docs/prompt-boundary-audit.md b/tools/stack-bench/docs/prompt-boundary-audit.md new file mode 100644 index 00000000000..4f797bd3656 --- /dev/null +++ b/tools/stack-bench/docs/prompt-boundary-audit.md @@ -0,0 +1,77 @@ +# Ecommerce prompt boundary audit + +This records the September 2026 product-prompt cleanup. It does not establish the +disclosure or qualification status of later definitions; review each frozen request. +The neutral no-repair condition measures expected behavior before failure feedback. +It must not be designed to make a chosen stack fail. All stacks receive the same product +work and equivalent application interfaces. Stack setup instructions remain stack-specific. + +## What changed + +Reviewed the selected modular feature requests and contracts across the dependency +graph, plus sequential L1-L3 framing and action fragments. The exact rendered dependency +request is checked for all three stacks at every depth. + +| Source | Removed from agent-facing product work | Retained | +|---|---|---| +| Stock transfers | Atomic quantity changes and conservation instruction | Move stock between named warehouses | +| Cancellation and returns | Explicit revenue reconciliation instructions | Cancel before shipping, return after shipping, refund/restock policy and visible order state | +| Payments and refunds | Retry deduplication and exactly-once instructions | Payment/refund display; successful refund resolves support case | +| Price changes and delivery | No-reload instructions and cancelled-order progression rule | Price editing, delivered state after 60 seconds | +| Support and recommendations | Cross-account isolation instructions | Product actions and recommendation ranking | +| Automatic reorder | Pending-work deduplication instruction | Threshold and restock inputs | +| Interface contracts | Repeated authorization, conservation, price and live-update instructions | Hooks, routes/reducers, identifiers, value formats, navigation and readiness | +| Sequential cart input | The adversarial quantity and explicit rejection instruction | Item identifier; scenario supplies its own quantity | +| Sequential framing | General real-time/restart/production guarantees | Current product scope and starting data | + +Expected specification documents remain unchanged. They are still available when a study +explicitly selects requested specifications. They do not enter neutral dependency requests. +No check, scenario, point value, or pass threshold was weakened by these prompt edits. + +## Necessary boundaries + +A product request still states what the product does: buyer reviews, cancellation before shipping, +reservations, stock scheduling, and account-related features. These semantics must be clear. +A statement such as "a shipped order becomes delivered after 60 seconds" defines the feature; +restart survival, duplicate execution, clock authority, and cross-account access do not need +implementation instructions in that request. Refund and restock policy remains explicit: a +return could otherwise reasonably enter quarantine rather than saleable inventory. Verified-buyer +reviews are a product policy, not a universal production guarantee. Keep that policy in the +request and measure its enforcement separately. + +An interface still needs deterministic names and formats. A readiness flag must distinguish +an empty result from a failed read. An action must be the actual UI action, not a separate +endpoint that can pass while the product is broken. Direct stock-table access remains because +external-write scenarios need a stable integration surface. These hooks reveal an operation's +existence, but must not state the expected security or synchronization policy. + +The cart quantity action reads its item identifier from the app. Its private scenario retains +the invalid quantity in the named action arguments. The shared executor already fills omitted +fields from those arguments; no new runtime path is needed. + +## Skills and interpretation + +Full TypeScript server and client skills are intentional study inputs. All SpacetimeDB +profiles must retain them, along with CLI and the selected dev workflow. Do not trim or +replace these skills based on the product-request boundary. The short product request +and the supplied SDK skills are separate inputs; material metadata records design advice +as present. Historical runs that omitted these skills do not represent the intended setup. + +Repairs report conclusive failures, including expected production behavior, with the +expected and observed result. They do not prescribe an algorithm or implementation. +Do not withhold a guarantee failure merely because it was not in the initial request. +A run with repairs measures assisted recovery. Use a no-repair condition for the +primary analysis of behavior supplied without failure feedback. A later depth's +first build can inherit earlier repair reports; it is not an independent no-repair trial. + +## Reporting and next validation + +Separate UI, feature, and production-quality checks. Report L3-only results alongside cumulative +results. A high cumulative percentage must not obscure an authorization or concurrency failure. +Some older feature packs contain production-quality checks, so category cannot be inferred from +pack type or scoring treatment. Classification and disclosure are separate axes. + +All affected definition evidence must be renewed. Do not relabel historical results as if they +used these requests. Validate the same checks on reference apps before publishing a verified +comparison. The next experiment must compare stacks under the same pinned prompts, guidance, +repair policy and budgets; it cannot assume which stack will fail. diff --git a/tools/stack-bench/docs/prompting.md b/tools/stack-bench/docs/prompting.md new file mode 100644 index 00000000000..98d5bd0a782 --- /dev/null +++ b/tools/stack-bench/docs/prompting.md @@ -0,0 +1,306 @@ +# Prompting method + +Stack Bench gives the coding agent a normal software request. It does not tell +the agent that it is in a benchmark. What Stack Bench asks for and what Stack +Bench measures are separate choices. + +## Prompt inputs + +Each request is assembled from these owners: + +| Input | Purpose | Owner | +|---|---|---| +| Product framing | Says whether to build a new app or add work to an existing app | Recipe | +| Current features | Describes the product work to implement now | Feature packs | +| Requested production behavior | States production requirements that the campaign chose to disclose | Specification packs | +| Stack material | Gives required access details and the selected level of technical guidance | Guidance profile and backend document | +| API reference | Supplies selected SDK material, including SpacetimeDB skills | Guidance profile | +| Starting data | Gives the new app's fixed catalog; later requests retain original entity names and relationships without resetting live data | Fixture | +| Application interface | Names the controls or operations needed for reliable use | Feature contracts | +| Repair report | Describes conclusive application failures from the last grade | Condition repair policy | + +The recipe and selected packs own the text. The prompt builder orders that text +and adds the small controller contract, such as the application directory, +listening address, start script, and completion response. + +## What the coding agent receives + +A new-build request has this shape: + +```text +Build the application described below and leave it running. + +Build the app in /app. +The web application must listen on 0.0.0.0. + +## Stack + + +## Selected API reference + + +## New application + + +## + + +## Starting catalog + + +## Application interface + +``` + +This is an abridged example. The exact request is composed from versioned files +and bound to the campaign by hashes. + +The new-build request does not include: + +- grader source or scenario files; +- check names, point values, expected scores, or comparison results; +- exact adversarial inputs chosen by a scenario; +- future dependency nodes that are not ready; +- production expectations assigned to the `expected` or `observed` treatments. + +## Features and production expectations + +A feature is product work. A production expectation describes how selected +features should behave under conditions such as reload, reconnect, concurrent +writes, authorization boundaries, or direct data changes. + +Each selected production expectation has one treatment: + +| Treatment | Included in request | Main score | Repair feedback | +|---|---:|---:|---:| +| `requested` | Yes | Yes | Yes | +| `expected` | No | Yes | Yes, after a conclusive failure | +| `observed` | No | No | No | + +`Expected` lets a no-repair study measure production behavior that was not +explicitly requested as a specification. The supplied features, interfaces, and +skills can still disclose related expectations. Audit their exact text before +claiming a behavior was supplied without being asked. + +`Observed` is a separate first-build diagnostic. It cannot change the main +score or steer repairs. + +### Example: expected durability + +The campaign selects account creation as current work. It also selects session +durability as expected production behavior. + +The coding agent sees product text such as: + +```text +## Accounts + +Visitors can create an account with a username and password. Returning users +can sign in, see which account is active, and sign out. +``` + +The request does not mention reload behavior. Stack Bench can still verify that +the signed-in session survives a reload. A conclusive failure affects the main +score and can produce repair feedback. + +### Example: requested durability + +The campaign selects the same account feature and changes durability to +`requested`. The request now also includes text such as: + +```text +## State durability: accounts + +A signed-in session survives a page reload as the same account. +``` + +The scored behavior is the same. Only disclosure changed. This makes the two +conditions comparable without changing the feature itself. + +### Example: observed durability + +The campaign changes durability to `observed`. The request again omits reload +behavior. Stack Bench measures it after the first build, records the result as +a diagnostic, and does not include it in the score or repair report. + +## Stack guidance + +Stack selection and guidance selection are separate. + +- Neutral guidance gives the required stack, connection details, startup + contract, and selected stack material. The coding agent chooses libraries, + architecture, and project structure within those requirements. +- Prescribed guidance can add design advice selected by the campaign. + +Neutral does not mean that the supplied skills contain no design advice. +The `neutral-dev` profile explicitly records `designAdvice: true` and includes +the intentional SpacetimeDB TypeScript server, TypeScript client, CLI, and dev +skills. Keep this material intact and retain its exact text in the evidence. +The experiment compares these delivered stack packages, not databases with +identical guidance. These skills are not grader source or scenario scripts. + +An abridged neutral PostgreSQL section is: + +```text +# PostgreSQL + +Use PostgreSQL for the application data. Choose the libraries, architecture, +and project structure. + +Use the supplied DATABASE_URL. Serve the application on the supplied port. +``` + +An abridged neutral SpacetimeDB section is: + +```text +# SpacetimeDB + +Use SpacetimeDB for the application data. Put the TypeScript module in the +required module directory. Choose the schema, libraries, architecture, and the +rest of the project structure. + +Use the supplied server URI, module name, CLI, SDK package, and web port. +``` + +## Application interfaces + +Feature contracts name stable controls or operations when deterministic use +requires them. They do not prescribe layout, data models, frameworks, or visual +design. The one data-shaped item a contract may name is an interoperability +surface that other systems write to directly, such as the stock tables; the +behavior expected around that surface stays in the specification. + +For example, the account contract names fields such as `signup-username` and +`signin-submit`. An HTTP stack also exposes the account operations through HTTP. +A reducer-based stack exposes the equivalent reducer operations. The product +behavior stays the same while the usable interface matches the selected stack. + +Scenario files own exact test data and edge-case values. Those values do not +belong in the product request or interface contract. + +## Dependency progression + +Dependency mode composes the request from features that are ready now. + +- A new app receives the framing, current root features, applicable requested + production expectations, starting data, and their interfaces. +- An upgrade receives the newly ready feature work. By default, it also retains + the interface contracts disclosed in earlier requests for the same app. +- Upgrades and repairs retain the original catalog names and relationships. + They explicitly do not reset current stock, prices, or user data. +- Earlier feature requirements are not repeated as new work. Retained contracts + do not claim that the earlier implementation passed its checks. +- Blocked descendants are not included until their dependencies pass. + +New dependency plans default `mode.retainPriorContracts` to `true`. The compiler +records this choice in the frozen plan. To compare incremental interfaces alone, +set the option explicitly: + +```json +"mode": { + "id": "dependency", + "workSelection": "progressive", + "retainPriorContracts": false +} +``` + +Campaign execution uses the frozen plan's setting. Set the option in the +campaign definition before compilation; it cannot be changed during execution. + +Retained contracts come from previously issued requests, not from grading +results. Each authored contract appears once. Future interfaces and undisclosed +production expectations are not added. The coding agent can refactor the app +while preserving its declared interface. This context is included in token +accounting and does not enable repair feedback. + +An upgrade therefore has three parts: the existing app context, the current +feature changes, and the applicable interface contracts. Existing compiled plans +and stored results are not rewritten. A changed prompt treatment requires a new +plan and separate comparison data. + +For example, if accounts and catalog items are ready, the request can include +those two features. Customer profile stays out until its account dependency +passes. A failure in the catalog path does not add or remove work from the +account path. + +## Repair requests + +A repair starts only after Stack Bench completes grading and records a +conclusive application failure. A repair report can name an expected +production behavior not stated in the initial request; that disclosure +happens only through the repair policy, after a conclusive failure, and under +the same rule for every stack. The coding agent receives a plain bug report: + +```text +Fix the reported application bugs. + +Expected: The signed-in account remains active after a reload. +Actual: The page returned to the signed-out state after reload. + +Change only what is needed. Do not alter behavior that is already correct. +``` + +The repair request also supplies the affected product area, current feature text, +application interface, and original catalog baseline. Provider failures, harness +failures, and interrupted work do not become application bug reports. + +Behavior feedback uses the authored expectation for that behavior, a finding from the +grader's closed catalog rendered as one sentence (a control that did not +appear, a number below its required value, a request that was accepted +when it had to be refused), and the application's own console errors. +Reports include measured quantities and expected results when they explain the +failure, such as two orders where one was expected. They retain the affected +control, missing or duplicate entries, and HTTP error statuses. They do not copy +scenario scripts, unrelated fixture data, or instructions for a particular +algorithm or data structure. + +Reports also name the recent completed controls and lifecycle actions when these +explain where execution stopped. A missing control before a reload, restart, or +server request is not evidence that the later durability or access check failed. +Keep that limit explicit instead of presenting the full requirement as an observed failure. + +The current repair policy records this disclosure as +`scenarioValues: "failed-observations"`. This changes the condition identity +from the earlier `"withheld"` policy. New plans must use the current identity; +old frozen plans and reports keep their original metadata. The value permits +exact expected and actual values only for the failed observations above. + +When setup fails, the report uses that setup's observation once, even if it +prevented several checks. It does not repeat the expectation of a later check +that never ran. Distinct failures remain separate. Console errors are supporting +observations from the same product area, not proof of a cause; duplicate lines +are removed. Initial feature requests still exclude scenario inputs. + +## Authoring rules + +No-repair runs measure behavior supplied without repair feedback. Normal repair +runs report observed failures and expected behavior, including production +guarantees, but do not prescribe algorithms or implementation changes. Their +results measure remediation, not unprompted guarantees. Earlier repairs also +carry into later levels and source-seeded campaigns. A later depth's first +build can therefore contain earlier repair guidance. Label it a pre-repair +checkpoint at that depth, not a fresh measure of unsolicited guarantees. + +Put positive controls in scenario setup. If setup fails, preserve that actionable +application failure and its setup phase. The check earns no credit, but the +failure does not prove that the later guarantee is broken. Repair feedback must +not claim that an unperformed authorization or integrity assertion failed. + +- Put product asks in feature prompts. +- Put optional production requirements in specification prompts. +- Put stable controls and operations in contracts. +- Put connection facts and API material in stack guidance. +- Put exact values and probes in scenarios. +- Never solve a check by adding its private input or expected implementation to + the request. +- Keep equivalent stacks equally informed about the product. +- Give every replay, forgery, or direct call a named application action that + declares both the HTTP route and the reducer. A campaign does not compile + while a selected check cannot be measured on a selected stack. +- Invalidate qualification tied to changed prompt inputs. Qualification comes + from matching evidence; do not add status fields to recipes or references. + +After a prompt change, run `npm run check:composition`, `npm run check:prompts`, +and the exact scenario check for the affected recipe. Inspect the rendered +request for every affected stack and depth. Do not run unrelated qualification +or paid work. diff --git a/tools/stack-bench/docs/research-roadmap.md b/tools/stack-bench/docs/research-roadmap.md new file mode 100644 index 00000000000..bfe54e2fc03 --- /dev/null +++ b/tools/stack-bench/docs/research-roadmap.md @@ -0,0 +1,360 @@ +# Stack Bench research roadmap + +This document defines the collection method. Campaign manifests and their evidence +record completed work and the next frozen protocol. This roadmap does not authorize +runs, qualification, or publication. + +## Decision and current position + +Measure how much model usage each defined stack needs to implement the same +product, and how much of the selected behavior it completes. Compare delivered +stack packages, including the intentional SpacetimeDB skills. This is not a +database-only experiment. + +The no-repair question is which expected production behaviors appear without +failure feedback. The repair question is how much completion and cost follow +actionable failure reports. Neither question sets a preferred stack's outcome. + +Use general-purpose names for shipped campaigns, commands, reports, and examples. +Describe the experiment or function, not a prospective customer or recipient. +Keep private delivery context in local notes. This naming rule does not change +the disclosed method, support conditions, exclusions, or evidence. Historical +run identities remain immutable in their original records. + +The baseline study uses dependency mode with progressive work selection and no +repairs or execution retries. Keep the graph, target depth, model, guidance, +budgets, repetition count, and concurrency in the frozen campaign manifest. +The model-free Docker demo is setup evidence, not agent performance evidence. + +Dependency depth comes from the feature graph. Progressive selection groups +available new work at each depth. Failed prerequisites block dependent features; +other branches can remain available. Previously completed behavior is checked +again as the app grows. Targeting a depth does not guarantee reaching every selected node. +Use the graph definition for its available depth range. Graph depths are not sequential L1/L2/L3 +product releases; keep those experiment names and denominators separate. + +Grading remains provisional. The recent source audit and selected reference +checks do not qualify the full selected dependency scope. Exploratory paid collection +can proceed before public qualification. A verified public comparison cannot. + +## Collection sequence + +Core storefront testing comes first: grading reliability, concurrent operations, +crash recovery, and applicable security checks. The unfinished address-book +migration is archived on `bradley/stackbench-migration-experiment` at +`50ad3a926`; it is not shipped in the core branch. Its code and retained evidence +are experimental, not qualified production coverage. It does not add to core +scores or gate core execution or qualification. Shared fixes retained in core +still need regression checks. Do not restore migration as part of core testing. + +Set sample counts from the study's purpose; a pilot count is not a statistical +power calculation. One block means one fresh attempt on each selected stack under the same +protocol. Repetitions start with clean apps and independent agent sessions. + +| Stage | Collection | Purpose and exit condition | +| --- | --- | --- | +| 1: measurement pilot | A balanced block on the selected stacks | Confirm that the harness produces valid measurements. Diagnose failures before scaling. | +| 2: initial comparison dataset | A fixed number of new balanced blocks under one frozen protocol | Show every result and its variation. Choose the count and concurrency before launch. | +| 3: focused confirmation | Separate frozen batch; size set after pilot variance and decision threshold | Test a stated claim with uncertainty. Freeze count, budget, exclusions, and analysis before launch. | +| 4: wider scope | Deeper dependency work, another product, or another model | Test whether findings extend beyond the initial condition. Keep each condition separate. | + +Keep pilots and revised cohorts separate. Do not replace original inputs or +increase an attempt's allowance after seeing its result. The time and money +limits cover the complete attempt, not each depth. They are ceilings, not price +or duration forecasts. Early blocking and regression checks change actual usage. +Do not extrapolate from sequential L1 by multiplying by three. + +Before each comparison batch, review the available evidence and freeze the exact graph, selected +checks, guidance, images, model, limits, and analysis. Keep repairs and retries +at zero for this comparison. If any protocol input changes, start a separate +dataset and disclose the change. Each additional batch needs authorization. + +If selected work is blocked, report it. A repair-enabled dependency study is a +separate optional experiment, with a new frozen allowance and all repair cost +included. It is not the baseline protocol. Its primary question is how much completion +and total model cost each stack achieves under the same repair allowance. +The no-repair baseline instead measures delivery without failed-check feedback. +Neither experiment assumes which stack will win. A claim that repairs improve +results needs separate comparable repair and no-repair cohorts. Comparing a +repaired app with its own earlier checkpoint alone does not isolate feedback +from additional work and model usage. + +### Optional future sequential experiment + +Sequential L1 covers the storefront, L2 adds operations, and L3 adds deferred +work. That runner requires a whole level to pass before advancing. It answers +a different question from the dependency study. No sequential study or +repair allowance is scheduled by this roadmap. A reference-seeded L3 upgrade +would be a further distinct experiment: verify its launch path, record baseline +provenance and excluded construction cost, and do not call it a fresh build. + +Do not weaken gates or give successful source to selected stacks merely to +produce higher-level scores. Reference-seeded and fresh-build outcomes must +have separate tables and claims. + +## Parallel execution and collection cost + +Three stacks by three repetitions gives nine attempts. Each campaign explicitly +sets its parallelism. Shared host capacity determines when the campaign can start; +it does not silently change the requested parallelism. +Declare concurrency before launch. Resource or credential admission can delay +dispatch; report that delay rather than silently reducing the experiment to +three parallel attempts. Resource leases are allocated automatically and do not +require a manually sized runner pool. + +Use the existing admission and resource controls. Verify the selected concurrency +against measured capacity; do not repeat successful capacity checks for unchanged conditions. +A balanced wave contains equal numbers of all stacks. Do not assign each stack +a different host or load level. +Use the existing balanced-rotation order and retain its seed. A seed controls +ordering; it does not make model generation deterministic. + +For each capacity step, retain Docker allocation, host/architecture, actual +concurrency over time, peak memory, CPU pressure, OOM events, disk availability, +provider throttling, phase wall time, and cleanup outcome. Separate configured +limits from measured usage. If a measurement is unavailable, say so. Do not +invent a RAM minimum. Stop increasing load on OOM, admission/ownership failure, +incomplete evidence, or saturation that prevents a fair comparison. Diagnose +the failed capacity step; do not rerun all earlier successful gates. + +Do not treat load-test timing and steady-load comparison timing as interchangeable. +Report infrastructure contention separately from application defects. If capacity +changes between study batches, retain batch identity and report results by batch. + +Before collection, choose a common per-attempt cap from observed usage plus a stated +headroom allowance. The maximum campaign authorization is attempts multiplied +by that cap, plus any explicitly authorized retries. Report the cap and actual +spend. Reaching the cap is an outcome, not permission to increase it mid-study. + +## Freeze the method before the main batch + +Use the compiled campaign manifest and its retained artifacts for machine-recorded fields. +Keep only the research question and analysis decisions not represented there in a small method +note beside it. Link the manifest; do not copy its fields into a second configuration. Record: + +- Research question, primary outcomes, sample count, stopping rule, and budget. +- Repository commit, image digests, platform, compiled plan and definition hashes. +- Model and adapter versions, provider route, context policy, and pricing snapshot. +- Exact agent-visible product request, contracts, stack material, and skills. + Retain the text as well as its hash. A hash cannot reconstruct missing content. +- Features and checks, requested/expected/observed specification roles, weights, + progression rules, repair disclosure, repair allowance, and retry policy. +- Host, resource limits, concurrency, ordering seed, dates, cache treatment, + and any other work sharing the host. +- Failure classes, exclusion rule, replacement rule, and report calculations. + +Keep the normal product request and expected production checks separate. Do not +expose scoring material to agents. STDB skills stay enabled and disclosed. Give +each stack the same opportunity to use its declared tools and supported setup. +If desired later, measure guidance as a separate ablation; it is not a condition +for accepting the main stack-package comparison. + +Never add runs until a preferred stack wins. Do not choose “representative” apps +after seeing scores. Preserve failures and costs from every execution. A harness +or provider failure is excluded from app comparison under the frozen rule, but +remains in the operational and spending tables. Report attempted, eligible, +excluded, stopped, and reached counts for every stack. Missing cost stays unknown. + +## Measures and analysis + +Keep cost and completion as two primary outcomes. Do not hide their tradeoff in +one composite score. + +Evaluate eligibility separately for each measure. A valid completed outcome can retain its +completion metric when exact cost is unavailable. Exact cost, an upper bound, and unknown cost +are distinct; never replace an unknown amount with zero. This does not waive run validation: +if missing receipts also prevent verification of the declared spending cap, the attempt has an +unresolved protocol issue and is not automatically eligible for comparison. + +Use the report's selected, passed, failed, blocked, and unmeasured counts. Its unmeasured count +does not distinguish all unattempted, deferred, and inconclusive checks. Use linked grade +evidence for those distinctions when available, and state when a breakdown cannot be recovered. +Do not infer attempted counts from selected minus blocked, or sum overlapping property groups. +Timing failures need evidence-based attribution; timing alone is not a harness failure class. + +| Measure | Required interpretation | +| --- | --- | +| Check completion | Passed / selected checks, with both counts. Weighted points remain separate. | +| Feature completion | Fully passed dependency nodes / selected nodes. A node with an unfinished guarantee is not fully complete. | +| Build checkpoints | Show each measured progressive build. For repair cohorts, separate pre-repair and repaired checkpoints and include all repair cost. | +| Feature and depth reach | Show nodes started, passed, failed, and blocked at each graph depth out of all assigned attempts. A reached depth need not mean all its nodes passed. | +| Full target delivery | Fraction of assigned attempts that passed the complete target; show exclusions separately. | +| API-equivalent cost | Use receipt status and frozen rates; distinguish exact, upper-bound, and unknown. It is not a subscription invoice. | +| Token usage | Separate ordinary input, output, cache reads, and cache writes; retain receipt-level cache-write durations. | +| Time | Show end-to-end wall time, planned pause time, and execution duration separately. Campaign timeout excludes verified planned depth pauses; provider waits still consume the allowance. Retain the raw timestamps. | +| Reliability | Harness/provider failures, evidence failures, OOMs, cleanup failures, and cap stops. | +| Regression | Previously passed checks lost after new work or repair, with source/checkpoint identity. | + +For dependency results, show node/depth completion and a separate whole-target +view using the frozen selected checks. Do not sum repeated checks across depths +as independent accomplishments. Work +not reached gets no completion credit; label it blocked, not measured app failure. +Do not report completion only among apps that reached depth 3. Validate the +denominator against the frozen selection and keep this research view distinct +from any existing report metric with different semantics. + +A pre-repair checkpoint at a later depth can inherit guidance from earlier +repairs. It is not an unsolicited-guarantee baseline. Preserve feedback history +when extending or seeding from an existing attempt. + +A planned depth pause must be declared in the original full-target plan. It +retains the live app, database, and cumulative budgets while the controller stays +running. It is not restart recovery. Database timers and external services can +advance during the hold. Compare staged and uninterrupted attempts as separate +conditions until evidence supports a narrower equivalence claim. A source-seeded +extension does not restore the original database or become a fresh 0-to-L3 run. + +Audit failures against the saved source, exact issued request, and check evidence. +Record the measurement stage (setup, assertion, blocked, or inconclusive), the +application cause, where the requirement was disclosed (current request, earlier +request, or not disclosed), and any unsupported harness assumption. These are +separate facts, not mutually exclusive blame labels. A missing interface can be +an app regression and expose a prompt limitation. Repeating its contract is a +testable treatment, not proof that the omission caused the failure. + +Do not count setup failures as measured backend defects. Report provider errors +separately, retain uncertain cost bounds, and require final validated progression +evidence before using a completed process as a completed comparison result. + +Total tokens count repeated processing, including cached input. They do not +measure unique prompt size or generated code. Show cost/completion scatter plots +and measured checkpoint curves. Do not interpolate unmeasured success between +checkpoints. Cost per passed check can be an appendix diagnostic, but is a poor +headline: checks differ in difficulty and a zero-score app has no finite ratio. + +For each comparison dataset, show every attempt, median, IQR, and mean cost. +State the small sample size beside each comparison. Use matched batch differences +to describe stack contrasts, while recognizing that model outputs are independent +draws, not identical seeded tasks. A check is not an independent sample; levels, +repairs, and regrades from one app are not new app builds. + +For confirmation, first choose the smallest decision-relevant cost difference +and completion difference. Use observed between-build variation to plan sample +size and precision. Analyze whole attempts/blocks, preserving their dependence; +do not bootstrap individual check rows. Predeclare primary contrasts and treat +other cuts as exploratory. Use an appropriate binomial interval for full-target +success rates, especially with small samples or zero failures. Three runs per +stack support a useful initial comparison, not a general claim of superiority. + +Blocking is a standard way to account for nuisance factors such as batch or +host conditions ([NIST](https://www.itl.nist.gov/div898/handbook/pri/section3/pri332.htm)). +Small-sample success-rate intervals need care; normal approximations can be +inaccurate ([NIST](https://itl.nist.gov/div898/handbook/prc/section2/prc241.htm)). + +## Failure review and defensibility + +Keep each failed check as an observation. Group checks under a common cause only +when logs, source, or a reproduction establish that cause. A group of failed +checks is not that many distinct bugs. Mark suspected causes as unresolved. + +Review app, harness, provider, and interrupted outcomes separately. Where feasible, +use the same reviewer rubric without stack labels, then disclose the source +needed to verify the diagnosis. Do not repair generated apps manually in the +primary dataset. Preserve the original grade before correcting a harness defect. +A regrade of unchanged source is paired diagnostic evidence, not another trial. +New prompt/interface requirements require a new cohort when old source is not +compatible. Never rewrite historical results to fit a later contract. + +Before a public comparative claim, obtain independent external review of the +frozen protocol, exclusions, scoring, and analysis. Record unresolved objections +and disclose reviewer affiliations. Parallel agent review is an internal check; +it is not independent external review or independent replication. Do not claim +replication until another team reproduces the method and reports its results. + +Before verified publication, qualify every selected check: a valid reference, +appropriate valid alternatives, declared defect controls, and the existing +null/release gates. Check qualification coverage for the exact reported selection. +Evidence for one recipe or depth does not qualify another. +Static mutation coverage is an inventory, not proof of defect detection. A live +control must fail at the intended assertion; setup failure, timeout, or missing +evidence cannot substitute. Repeated clean reference passes check repeatability, +but do not prove that timing failures are impossible. See the +[reference qualification guide](../reference-apps/README.md) for exact scope and +repetition requirements. +Keep provisional evidence available with its label while this work +proceeds. Explicitly justify expected production requirements and check weights; +do not claim that this finite test proves an app is production-ready. + +## Research pack and durable archive + +Aim for a 4–6 page decision report, a one-page run guide, and linked evidence. +Page count is a reading target, not a limit on the data retained. + +The decision report should contain: + +1. Scope and method, including intentional skills and qualification status. +2. Cost versus completion for every attempt, colored by stack. +3. Feature and selected-depth reach, completion, blocked work, and build checkpoints. +4. Cost/token breakdown and observed variation, with sample counts. +5. A short failure table with confirmed causes and linked evidence. +6. Limits, exclusions, and the next experiment that would change the decision. + +Ship the existing HTML report and validated JSON, frozen plan, method file, +attempt-level CSV, and manifest-listed artifacts with their relative paths intact. +The CSV should identify campaign, block, attempt, execution, stack, model, +condition, level, source/definition hash, outcome, passed/selected counts, +weighted points, repair count, cost status/value, token buckets, duration, and +evidence path. Use one row per attempt-level checkpoint where needed; do not +count those rows as independent attempts in analysis. + +The `export-manifest.json` is an index, not a portable archive. The +`campaign export --out ` command copies +its listed public artifacts and adds attempt/execution CSVs using existing report +owners. It omits source trees, raw transcripts, media, and external evidence; +links to omitted files cannot work offline. Check included links and hashes. Add a +separately reviewed source/prompt archive if claiming full reconstruction. The +complete campaign copy described in the [appliance guide](../appliance/README.md) +is an internal backup; it is not automatically safe for public distribution. + +Keep full original campaign evidence privately: all receipts, prompts, source +checkpoints, grades, logs, media, admissions, resource records, exclusions, and +qualification evidence. For external sharing, review free text and generated +source for credentials and private data. Exclude private authority, provider +credentials, and environment secret files. Record omissions. Retain immutable +originals and hash the shared pack. Full transcripts and every screenshot belong +in the evidence archive, not in the report body. + +The run guide must distinguish the free reference demo from a paid model campaign. +Include the tested Docker command, platform requirements, credentials needed for +paid work, budget controls, output location, and how to inspect/copy results. +Rebuilding the same plan must be possible; identical stochastic outputs are not +promised. + +## Agent and model support + +The registry includes Claude Code, Codex, and OpenRouter adapters. Registration +is not qualification of every model, credential route, or execution mode. +Before collection with a new adapter condition, verify its declared launch, +repair, continuation, usage, budget, and failure paths with matching evidence. +Any live pilot needs separate authorization. + +Keep provider, model, agent runtime/version, tools, reasoning settings, and +context policy distinct in the frozen condition. Preserve and disclose the +intentional SpacetimeDB skills. Compare stacks within each condition; do not +pool different agent conditions into an unexplained stack average. Evidence +from one model does not establish results for another. + +## Methods references + +[NIST AI RMF Measure](https://airc.nist.gov/airmf-resources/playbook/measure/) +supports documented measurement validity and independent review. +[NIST: Expanding the AI Evaluation Toolbox with Statistical Models](https://www.nist.gov/publications/expanding-ai-evaluation-toolbox-statistical-models) +distinguishes fixed-benchmark accuracy from generalized performance; correlated +checks from one app are not independent experimental replicates. + +## Parallel work assignments + +Use existing owners. No research service, scheduler, or new frontend is needed. + +| Owner | Bounded task | Completion evidence | +| --- | --- | --- | +| Orchestrator | Freeze questions, campaign manifest, budget proposal, and analysis rules | Reviewed compiled plan and method file before any new paid launch | +| Agent A: definitions | Audit/qualify the exact selected dependency checks and expected-spec justifications | Matching source audit and, when separately authorized, qualification evidence; explicit remaining gaps | +| Agent B: report | Derive CSV and copy manifest-listed artifacts through existing report/export code | A small saved-fixture check for row counts, costs, hashes, and portable links | +| Agent C: operations | Retain capacity and wall-time evidence through existing runtime owners; prepare next capacity step | Measured limits and failure reasons; no unsupported RAM or throughput claims | +| Orchestrator/reviewer | Review completed attempts, resolve classifications, assemble the report | All assigned attempts accounted for; report totals match receipts and grades | + +Agents can do source/pack work while paid attempts run. Shared runtime or grader +changes apply to a new frozen cohort. Do not rebuild or replace the active runner +under a collecting campaign. Request separate authorization for each concrete +paid or long-running gate; this roadmap alone does not start them. diff --git a/tools/stack-bench/docs/stack-bench.html b/tools/stack-bench/docs/stack-bench.html new file mode 100644 index 00000000000..1b12d4df209 --- /dev/null +++ b/tools/stack-bench/docs/stack-bench.html @@ -0,0 +1,1806 @@ + + + + + +Stack Bench + + + + +
+ +
← → or scroll
+ + +
+
+ + SpacetimeDB +
+

Stack Bench

+

Build the same product on different app stacks. Test what works and compare the evidence.

+
+ + +
+
what it includes
+

Stack Bench manages the full workflow.

+

One system runs the build, tests the finished product, supports optional repairs, and preserves comparison evidence.

+
+
+ +

AI build runner

+

Runs the selected model with the product brief, stack, and budget.

+
+
+ +

Modular product spec

+

Versions features, dependencies, prompts, checks, and scoring rules.

+
+
+ +

Isolated stack runtime

+

Starts the generated app and selected stack services in controlled containers.

+
+
+ +

Automated grader

+

Exercises real user flows, direct data changes, failures, and concurrency.

+
+
+ +

Repair controller

+

Returns observed failures when the plan enables repairs.

+
+
+ +

Evidence and comparison

+

Packages source, prompts, scores, cost, screenshots, video, and traces.

+
+
+
+ + +
+
one controlled run
+

Stack Bench controls every step.

+

Each run keeps the request and environment fixed, isolates the build and services, and saves the results and evidence.

+ + + Stack Benchcontrols the run + preflightchecks setup first + agentbuilds or fixes + app stackselected for the run + buildisolated workspace + servicesisolated and reset + apprunning on the selected stack + graderruns the product tests + resultspass · fail · could not test + evidenceprompt · source · cost · visuals + + + + failed testsreturn to the agent + +
+ + +
+
the run plan
+

Each run starts with a fixed plan.

+

Choose the model, stack, features, tests, and repair limit. Stack Bench records the plan and builds the request the agent receives.

+ + + + + + + + + + + + Model + provider + exact model + + + + Stack + selected stack + tools + + + + Features + unlocked for this level + + + + Tests + checks + scoring + + + + Repairs + limit for each feature + + + + + + + + + + + BUILD, ADD, OR FIX + Work on the current features + + + Product brief + app + current features + Stack access + connection details + API reference + selected SDK material + Testing interface + hooks + lint command + + + On repair: one feature + its failed tests + +
+ + +
+
how testing works
+

Stack Bench tests the finished product.

+

The grader uses real browser sessions, direct data changes, service interruptions, and concurrent actions, then checks both visible and persisted state.

+ + + REAL USER FLOWSmultiple browser actors + ACCESS + OWNERSHIPprotected and cross-account actions + DURABILITY + RECOVERYreload · reconnect · restart + APP UNDER TEST + LIVE STATEdirect data changes reach open pages + CONCURRENCYoverlapping actions · exact totals + OPERATIONS + ACCOUNTINGshipping · pricing · revenue + +
+ + +
+
optional repair and retest
+

Failed tests return to the agent.

+ + + + + + + + + start level + dependencies passed + + + build + current features + + + test + unlocked features + + + all pass? + + + continue + next level opens + + + repairs left? + + + repair + one failed feature + + + that path stops + other paths continue + + + + + + yes + + + no + + yes + + + + none + + + continue with passed paths + +
+
levelL1L2
+
feature repairs0 of 31 of 3
+
features passed2 of 124 of 12
+
cost$0.00$3.20$6.40
+
+

This example uses a repair limit per feature and one feature per repair. The plan can disable repairs. A completed coding repair uses one repair, even if grading later fails. Provider errors and interrupted coding use none.

+
+ + +
+
dependency mode
+

Working features open the next work.

+

A feature can move forward when its product behavior works. Production checks still affect its score. A failed feature blocks only the paths that need it.

+ + DEPTH 1 + DEPTH 2 + DEPTH 3 + + + + + + + + + + + accountsOPENWORKINGPASS + catalogOPENWORKINGFAIL + cartOPENWORKINGPASS + warehouseOPENWORKINGPASS + + operator accessOPENWORKINGPASS + searchBLOCKED + checkoutOPENWORKINGFAIL + stock transfersOPENWORKINGPASS + + account recoveryOPEN + recommendationsBLOCKED + returnsBLOCKED + scheduled restocksOPEN + +
+ + + + + +
+
testing the benchmark
+

Stack Bench tests itself.

+

The same selected checks run against controlled apps. A correct app must pass, a planted defect must fail its target, and an empty app must score zero. Full qualification remains pending; these diagrams show the required outcomes.

+ +
+ + +
+
results
+

Scores show where each stack works.

+

Illustrative scores, not measured results. Each questline has its own score. Blocked and unfinished work stays in the denominator.

+ +
+ + +
+
comparison
+

Compare score, cost, duration, and repairs.

+

Illustrative comparison, not measured results. Each stack uses the same plan. The report separates first-build results, optional repairs, and cost.

+ +
+ + +
+
evidence
+

Every run preserves its evidence.

+

Open the exact result, source, visuals, and run economics behind the score.

+ +
+ + + + diff --git a/tools/stack-bench/docs/system-design.md b/tools/stack-bench/docs/system-design.md new file mode 100644 index 00000000000..67039dbc319 --- /dev/null +++ b/tools/stack-bench/docs/system-design.md @@ -0,0 +1,122 @@ +# Stack Bench system design + +Stack Bench turns one versioned test plan into traceable comparison evidence. The +system must make every decision, action, result, and cost traceable without +using chat history or operator memory. + +## One owner for each fact + +| Layer | Owns | Durable output | +|---|---|---| +| Definitions | Product work, prompt modules, checks, stacks, models, and budgets | Versioned source files | +| Compiler | The exact work matrix and all bound identities | `plan.json` | +| Job store and worker | Immutable submission, host placement, credential references, and exclusive execution claim | Job and claim records | +| Admission | Whether the exact plan can run on this appliance | Admission artifact | +| Scheduler | Attempt order, concurrency, continuations, and terminal state | `state.json` | +| Run engine | Build, grade, repair, resource ownership, and cleanup | Attempt directory | +| Grader | Typed check results and evidence | Grade artifacts | +| Progression engine | Open, passed, failed, and blocked features | `progression-state.json` | +| Report | A reproducible view of retained evidence | `report.json` and `report.html` | + +No layer can silently replace a decision from a layer above it. A view can +summarize durable data, but it cannot create new run state. + +## Data flow + +```text +versioned definitions + | + v +compiled plan -> admission -> scheduler -> run engine -> grader + | | | + v v v + state.json run.json evidence + \ | / + \ v / + -> inspection -> report +``` + +The coding agent receives only the app request, current work, selected stack +material, and repair evidence allowed by the plan. It does not receive the +benchmark, grader, future work, expected implementation, or comparison data. + +## Operator loop + +An operator, human or agent, uses one loop: + +1. **Define.** Select one versioned campaign file. Do not rebuild the plan from + command flags. +2. **Validate.** Compile it and inspect the exact attempts, stacks, model, + prompt policy, checks, points, budgets, images, and parallelism. +3. **Admit.** Prove credentials, images, ports, resource capacity, and stack + access before model work starts. +4. **Run.** Start the exact stored plan or use an eligible continuation. A paid + action is always explicit. Resume is not general process or database recovery. +5. **Observe.** Read durable campaign state first. Open logs only to diagnose a + live phase or failure. +6. **Decide.** Continue only through a legal state transition. Never hide an + invalid attempt or retry it outside the frozen policy. +7. **Report.** Generate the result from retained run evidence. Publish it as + verified comparison data only when grading qualification is complete. +8. **Clean.** Remove temporary owned resources. Keep the campaign package. + +The CLI and dashboard use the same compiler, scheduler, state reader, and run +commands. The dashboard is a view and input surface. It is not another control +plane. + +## Agent interface + +The operator interface must answer these questions without source inspection: + +- What exact plan am I controlling? +- Can it start without spending model usage? +- What is running now, and in which phase? +- What has it cost and how long has it run? +- Which results are valid application results? +- Which failures belong to Stack Bench, the provider, the stack tools, the + host, or the operator? +- What evidence proves each answer? +- Which actions are legal now? + +Machine-facing commands return stable JSON. A compact response gives the plan +identity, campaign state, active work, cost, failures, and legal next actions. +Detailed responses add attempts and artifact paths. Logs and raw artifacts stay +available, but an operator does not need to parse them for normal control. + +Errors must name the failed subsystem, failure owner, retryability, retained +evidence, and next safe action. `inconclusive` is an intermediate measurement +state, not an accepted final explanation. + +## Resource rules + +- Compile and inspect before any model call. +- Run focused source checks after a change. Run the integrated source gate once + for the final source identity. +- Reuse qualification evidence only when its bound inputs match, or a validated + evidence slice proves unchanged scope and a reviewed executable equivalence + decision covers any runtime hash change. Preserve the original artifacts. +- Do not repeat reference, mutation, or null work for unchanged scope. +- Stop new paid attempts after a harness, provider, host, or operator failure. +- Retry only when the frozen attempt policy permits it. Extra repair grants + require a separate operator action. +- Run independent attempts in parallel only within the plan and admitted host + capacity. +- Preserve a failed package before a source or plan change. + +## Accumulated knowledge + +Operational knowledge belongs in typed artifacts, not chat transcripts or a +growing journal. Each completed action records its inputs, identity, outcome, +cost, duration, evidence paths, and owner. A later operator can reconstruct the +campaign from the retained package. Continuation still requires the engine's +eligibility checks; evidence alone cannot restore a lost live database or session. + +Local notes can explain an active investigation. They cannot authorize a run, +change a score, or replace a missing artifact. + +## Design test + +Every major structure must have one purpose, one owner, and one current +consumer. If its reason cannot be stated in one sentence, simplify or remove it. +Complexity is allowed only when it protects result validity, isolation, +security, recovery, or a current operator need. diff --git a/tools/stack-bench/docs/technical-guide.html b/tools/stack-bench/docs/technical-guide.html new file mode 100644 index 00000000000..4f965e6f656 --- /dev/null +++ b/tools/stack-bench/docs/technical-guide.html @@ -0,0 +1,222 @@ + + + + + + Stack Bench — technical guide + + + +
+

Stack Bench / Technical guide

+

From product request to measured result

+

How Stack Bench compares coding agents across technology stacks, controls the experiment, and retains the evidence behind each result.

+ Documentation index +
+ +
+
+

One run path across stacks

+

Each attempt builds the same selected product work on one stack. The controller uses shared campaign, grading, and repair logic. Stack adapters supply the database and runtime operations.

+
    +
  1. DefineSelect work, guidance, checks, model, and budgets.
  2. +
  3. CompileFreeze the work matrix and its input identities.
  4. +
  5. PreflightCheck the runner and activate isolated resources.
  6. +
  7. BuildGive the agent the current product request.
  8. +
  9. Grade / repairMeasure behavior and apply the chosen repair policy.
  10. +
  11. RecordKeep source, outcomes, cost, time, and cleanup evidence.
  12. +
+

Application failures, provider failures, and harness failures remain separate. The report reads saved evidence; it does not infer success from an agent's final message.

+
+ +
+

What the experiment fixes

+
+

Product and checks

The track defines the product. Feature packs supply requested work and required interfaces. Specification packs supply expected production behavior. A recipe selects the modules and checks.

+

Delivered guidance

A condition selects stack material, SDK skills, disclosed specifications, and repair feedback. These are recorded inputs to the comparison.

+

Execution policy

The campaign fixes models, stacks, repetitions, parallelism, time and cost limits, repair budgets, images, and pricing. Compilation binds their identities.

+
+

Compare compatible stack–agent–condition groups. SpacetimeDB's TypeScript server, client, and CLI skills are intentional parts of its delivered package. This measures the complete package used by the agent, not the database in isolation.

+

Research method and comparison rules · Definition ownership

+
+ +
+

What the coding agent receives

+
+

The product request

  • The brief and current feature work.
  • The original catalog names and relationships.
  • Required application controls or action interfaces.
  • Selected stack access details, SDK references, and skills.

Later requests retain disclosed contracts and catalog facts without resetting live application data.

+

A repair request

When enabled, feedback gives the affected behavior, expected result, and observed failure. It can report a failed production expectation even when the initial request did not state it.

Feedback does not prescribe an implementation. Grader source, test scripts, scores, and comparison results stay with the controller.

+
+

No repairs measures behavior before failure feedback. With repairs measures completion and cost after that feedback. A later depth's first build can inherit earlier repairs, so it is not a fresh no-repair sample.

+

Claude Code, Codex, and OpenRouter use registered adapters and shared execution controls. Adapter registration alone is not live model qualification.

+

Prompt and repair policy · Disclosure review · Provider credentials

+
+ +
+

How work advances

+

Sequential mode completes each selected level before the next. Dependency mode opens a feature when its required parents pass. A blocked branch does not prevent unrelated branches from advancing. Earlier work is checked again for regressions.

+
+

Work selection

  • feature: one ready feature.
  • progressive: all currently ready features.
  • all-at-once: the full selected graph.

The graph owns prerequisites. Work selection does not change the scored target.

+

Repair selection

Repair one failed feature or a batch of current failures. Limits can apply to the attempt, feature, or depth. When combined, the tightest remaining limit applies.

The unchanged-failure limit is separate. The initial failure counts as one observation; pure regrading does not spend a repair.

+
+
  1. Save the source checkpoint and grade the selected work.
  2. If repairable failures and budget remain, send the allowed failure report.
  3. Grade the changed source and check prior behavior for regressions.
  4. Accept the candidate under the mode's rules, or restore accepted source. Keep the rejected candidate as evidence.
+

A dependency gate determines whether child work can open. Full feature completion is stricter: all its selected checks, including production guarantees, must pass.

+

Explore the dependency graph · Run and repair options

+
+ +
+

How execution stays separate

+
+

Attempt isolation

Each attempt owns its containers, database, ports, workspace, and resource lease. Coding agents do not receive the grader, result store, provider secret files, or Docker socket.

+

Job dispatch

A job runs one campaign on one host. Local workers claim queued jobs. Campaign parallelism controls attempts; worker concurrency controls campaigns. Resource leases are allocated on dispatch.

+

Credential selection

Named profiles select credentials per attempt or adapter. The trusted broker holds the secret and records usage. Selection is explicit; the system does not rotate accounts automatically.

+
+

There is no manually sized runner-slot pool. Host resources and provider limits still constrain execution. The local worker does not provide a distributed attempt scheduler or account-wide quota service.

+
Optional SpacetimeDB development workflow

neutral-dev supplies guidance for the agent to run spacetime dev. neutral-managed-dev supplies the /deps/spacetime-dev start|status|stop helper. The agent creates project configuration and starts the watcher. Both keep the TypeScript server, client, and CLI skills.

These are different recorded guidance treatments. Neither changes grading or repair policy.

+

Pause, stop, and continuation

+
+ + + + +
MethodWhat it preservesBoundary
Planned depth pauseThe live app, database, execution, and cumulative budgets.Declare the full target and pause depth before launch. Keep the controller running. Database timers still advance.
Stop and reconcileSaved evidence and private cleanup authority.Interrupts work. It does not restore the lost agent session or database runtime.
Source-seeded extensionVerified source and parent lineage.A separate campaign with fresh runtime and budgets. Earlier work is regraded. Include parent cost when reporting the full path.
+

A planned pause excludes its verified hold time from the working allowance. It does not establish equivalence to uninterrupted execution. A controller shutdown cannot be recovered as the same live pause.

+

Workers and jobs · Credential profiles · Depth pause commands · Cleanup and recovery

+
+ +
+

How to read a result

+

Each selected check records an outcome and its supporting observations. Only conclusive application failures can enter a repair report.

+
+ + + + + +
OutcomeMeaningTreatment
PassedThe measured assertion was met.Earns its selected points and completion credit.
FailedThe application did not meet the assertion.No credit; eligible for feedback under the repair policy.
InconclusiveThe evidence cannot establish pass or fail.No credit or application blame; retain the reason.
Harness failureThe test system could not perform a valid measurement.No credit or application repair request; diagnose the harness.
+
+

Check completion

Accepted passed checks divided by all selected positive-point checks.

+

Feature completion

Fully passed dependency nodes divided by all selected nodes.

+

Weighted score

Accepted passed points divided by all selected points.

+
+

Blocked and unmeasured work stays in the denominator. Feature, production, and interface categories describe checks; they are separate from the Features/Checks counting unit.

+

Cost includes build and repair work. Keep exact, upper-bound, and unknown receipts distinct. Subscription usage uses frozen API-equivalent rates, not a subscription invoice. Report wall time, planned pause time, and execution duration separately.

+

The dashboard switches between completion, cost, and distribution, with stack and repetition toggles. Features are selected by default. Lines connect saved observations, not continuous measurements. Open an attempt for checks, source, screenshots, logs, and the agent transcript.

+
Evidence retained with the run
  • plan.json: the compiled experiment and input identities.
  • state.json: attempt scheduling and execution history.
  • run.json: build, grade, repair, cost, and outcome records.
  • progression-state.json: feature state and event history.
  • Grade artifacts: actions, expected and observed values, and media.
  • recovery.json: cleanup outcome and retained resource evidence.

Keep the complete campaign archive. The public research export is a smaller package and can omit source, transcripts, and media.

+

Dashboard guide · Categories and counting units · Analysis and reporting

+
+ +
+

What makes a comparison defensible

+

The selected checks need matching live evidence. A successful build, a static mutation inventory, or an older report does not qualify a changed definition.

+
+

Correct reference

The known-good application must pass the selected scope on each stack. Use the calibration's repetition count. Extra repeats can check stability.

+

Known defects

Each mutation must change observable behavior and fail its declared assertions. Setup errors and unrelated failures do not count as a clean catch.

+

Empty application

An empty app must fail the selected scored checks conclusively. Zero points caused by a broken harness are not a valid control.

+
+

Scope of the claim. These are finite behavioral tests. Runtime restart does not establish power-loss or database crash recovery. A bounded contention burst does not establish sustained capacity. Review the exact probe and delivered request before attributing a result to an unrequested production guarantee.

+

Qualification is determined by the frozen definition and matching artifacts, not a status table in this guide. Pending qualification permits provisional runs but blocks verified comparison claims. Report exclusions and missing measurements separately.

+

Qualification commands · Probe coverage and limits · Research protocol · Release verification

+
+ +
+

Where to make a change

+

Use the existing owner for each concern. The source is TypeScript; builds emit ESM JavaScript into dist/.

+
+
  • src/campaigns/Plan compilation, scheduling, jobs, budgets, and reporting.
  • src/progression/Feature dependencies, work selection, repair state, and event history.
  • src/composition/Pack and recipe compilation, prompt composition, and bound identities.
  • tracks/Product work, interfaces, scenarios, and feature graphs.
+ +
+

Start with a focused test for the changed boundary. Run live Docker or qualification checks when that boundary needs them; do not repeat unchanged evidence for reassurance.

+

Development and test commands · Add or change a feature and its checks · Ownership and system design

+
+
+ + + diff --git a/tools/stack-bench/grader/README.md b/tools/stack-bench/grader/README.md new file mode 100644 index 00000000000..f597a74ef14 --- /dev/null +++ b/tools/stack-bench/grader/README.md @@ -0,0 +1,180 @@ +# Stack Bench grader + +The grader runs versioned scenarios against a generated app. It collects +browser, transport, lifecycle, and database evidence for each check. + +Each scenario actor receives a separate browser context. A live-update check +passes only when the page that was already open changes. The grader does not +reload a failed assertion and try again. + +## Outcomes and scoring + +Every check produces one outcome: + +- `passed`; +- `failed`; +- `inconclusive` when required evidence is unavailable; +- `harness_failure` when Stack Bench could not perform the measurement. + +Only a passed check adds its declared points. Other outcomes add zero and never +change the declared denominator. Console errors remain diagnostics and do not +change unrelated scores. + +Authorization and replay checks pass only when the requested call ran and +produced verifiable evidence. Visible UI behavior cannot replace missing server +evidence. + +## Fault probes + +The current campaign checks do not yet include controlled checkout write rejection +or forced scheduled-worker overlap. The rules below govern adding those probes; +they are not a claim of current coverage. + +The purchasing and cart contracts do not fix order storage or ID generation. +An ID-collision probe verified on one saved app therefore cannot be applied to +all generated apps. Do not require sequential IDs just to make that probe work. +A general write-rejection probe needs an external fault method that supports the +app's actual storage, with proof that the intended write was rejected. + +A database stall tests recovery from a stall. It does not by itself prove a late +write failed or that two workers selected the same job. Keep those claims distinct. + +Scored fault probes leave the generated source and dependencies unchanged. Inject +faults through the isolated runtime or database, then check persisted application +state. Record the fault target, activation, release, and observed result. A setup +timeout or an unobserved fault is not an application failure or a pass. + +Use instrumented copies only as grader controls, with their changes recorded. +Before promoting a probe, require normal-operation success, a known defect caught +at the intended check, a correct implementation passing under the same fault, +and successful recovery after release. An unsupported stack is not a passing +control; do not include the probe in a shared comparison until each stack has a +verified method for testing the same behavior. + +A duplicate-checkout test does not establish rollback after a failed order write. +A restart test does not establish safety when scheduled workers overlap. Keep +those cases separate in check definitions and reported coverage. + +Confirm the delay on at least one worker. Do not require a second worker to reach +the same write: correct job claiming can prevent it. Verify the final effect after +release, and check that a later poll does not repeat it. + +## Failure reports + +An action never fails with a sentence. It fails with a finding from the closed +catalog in `src/actions/action-findings.ts`: a kind and its fields, where a +field is a contract control name, an action id, an actor label, a number, a +count, or an HTTP status. Every reader renders the finding from its one +template. Raw diagnostics travel in a `detail` field that is never rendered. + +## Scenario ownership + +Scenario JSON contains actors, setup steps, actions, and scored checks. The +action contracts are compiled and registered in `src/actions/`. Scenario prose +is not executable behavior. + +Actions run through capability-scoped executors. Browser, transport, +concurrency, lifecycle, and database actions use the same typed result contract. +Each stack adapter declares the capabilities it provides and whether named +application actions travel as HTTP routes or reducer calls. The campaign +compiler resolves every selected check against every selected stack and +refuses a campaign that a stack could not measure. + +When authoring assertions: + +- scope repeated elements to their owning row, room, message, or user; +- assert visible values, not the presence of an empty container; +- require the original open page for live-update behavior; +- use separate actors for identity boundaries; +- say in the criterion's `note` why it carries its points when they differ + from the feature's other criteria. + +Example: + +```json +{ + "do": "expect", + "actor": "bob", + "testid": "unread-badge", + "in": { "testid": "room-item", "contains": "{room:unread-main}" }, + "within": 5000 +} +``` + +## Run the grader + +Use `dist/commands/run-suite.js` for normal grading. It owns database reset, +provenance checks, contract linting, scenario execution, logs, and bundle +creation. + +Direct `dist/grader/grade.js` execution is for focused scenario authoring only: + +```bash +node dist/grader/grade.js --url http://localhost:6173 \ + --spec tracks/ecommerce/scenarios/01-account-create.json \ + --label spacetime-l1 --out report.json +``` + +If the grader exits before writing JSON, inspect the retained +`grader-.stdout.log` and `grader-.stderr.log` files. + +## Validate checks + +Live reference runs test that intended behavior passes. Null controls test that +an empty app fails each selected scored check conclusively. Live mutations test +that each selected check detects its assigned defect. These are finite controls +for an exact definition, not proof of general production readiness. + +This command checks mutation definitions and source anchors only. It does not +start an app or show that the grader detects a defect: + +```bash +npm run check:mutations -- --app --mutations +``` + +For live controls, use the scoped commands in the +[reference guide](../reference-apps/README.md#live-qualification). Declare the +recipe and depth explicitly. A bare default command can measure a different scope. +During development, run only affected mutations. The full selected mutation set +is a release qualification gate and requires separate authorization. + +The mutation runner requires: + +- a fully passing clean baseline; +- one exact source anchor for every edit; +- a conclusive failure at the intended check; +- no unrelated failures; +- successful source restoration and app reset. + +Setup, infrastructure, and inconclusive failures do not count as defect +detection. A surviving mutation can be equivalent, so confirm that its source +edit changes observable behavior before changing the check. + +For concurrent checks, a defect control must preserve ordinary serial behavior. +For restart checks, ordinary execution must work before the restart. A disabled +operation does not isolate a race or a restart defect. Keep the baseline, +mutation source, action evidence, and cleanup outcome together. A control for one +defect does not validate all alternative implementations or failure modes. + +## Media evidence + +`--media ` records videos and failure screenshots. `--trace` adds a +Playwright trace with DOM and network snapshots. + +```bash +npx playwright show-trace +``` + +Inspect the failing actor's evidence before attributing a failure. Media belongs +with run output and is not tracked in the repository. + +## Execution target + +Preflight binds the stack adapter, database or module name, ports, container +identity, and run lease. The suite runner verifies that exact target before +grading. A mismatch is a harness failure and cannot produce an application +score. + +When several stacks fail the same check, inspect the structured evidence. A +shared failure is useful diagnostic information, but it does not prove whether +the apps or the check are wrong. diff --git a/tools/stack-bench/grader/grade.ts b/tools/stack-bench/grader/grade.ts new file mode 100644 index 00000000000..8fcced1797f --- /dev/null +++ b/tools/stack-bench/grader/grade.ts @@ -0,0 +1,1142 @@ +#!/usr/bin/env node +/// +// Score declared criteria from one observed run in isolated actor contexts. +// +import { chromium } from 'playwright'; +import { attemptBrowserLaunchOptions } from '../container/browser-pipe.js'; +import type { Browser, BrowserContext, Page, Request } from 'playwright'; +import { sanitiseConsoleError } from '../src/evidence/diagnostic-sanitizer.js'; +import { inspectSavedDiagnostic } from '../src/runtime/saved-diagnostic.js'; +import { randomUUID } from 'node:crypto'; +import { readFileSync, mkdirSync } from 'node:fs'; +import { basename, join } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { parseArgs as parseNodeArgs } from 'node:util'; +import { harnessBrowserFailure, harnessProcessFailure, + runBrowserInfrastructureOperation } from '../src/evidence/harness-errors.js'; +import { compileScenarioDefinition } from '../src/composition/definition-compiler.js'; +import { materializeScenarioCredentials } from '../src/composition/credential-aliases.js'; +import { loadTrack } from '../src/composition/tracks.js'; +import { isFinding } from '../src/actions/action-findings.js'; +import type { Finding } from '../src/actions/action-findings.js'; +import { recipeArtifactIdentities, writeArtifact } from '../src/evidence/artifacts.js'; +import { resolveCalibrationForRelease } from '../src/composition/calibration-compiler.js'; +import { resolveGradeRecipeArtifactBinding } from '../src/composition/recipe-release.js'; +import { selectScenarioChecks } from '../src/composition/recipe-selection.js'; +import { ACTION_REGISTRY } from '../src/actions/action-catalog.js'; +import { ActionApplicationFailure, ActionInconclusive, executeAction } from '../src/actions/action-contract.js'; +import { runApplicationNavigation } from '../src/actions/browser-navigation.js'; +import { createCheckEvidence, evidenceIsMeasured, evidencePassed } from '../src/evidence/check-evidence.js'; +import { evidenceNowMs } from '../src/evidence/evidence-timing.js'; +import { renderEvidenceConsoleLine } from '../src/evidence/evidence-presentation.js'; +import { measureGradePackRuntime } from '../src/composition/pack-runtime.js'; +import { STACK_ADAPTER_REGISTRY } from '../src/stacks/stack-adapters.js'; +import { stableElementSelector } from '../src/actions/element-selector.js'; +import { + createNamedActionsCapability, +} from '../src/actions/actor-transport-action-executors.js'; +import type { ConcurrentCallResult } + from '../src/actions/actor-transport-action-executors.js'; +import { + createDatabaseWriteCapability, + createDatabaseReadCapability, + createLifecycleCapability, +} from '../src/actions/runtime-action-executors.js'; +import { requireLeasedDatabase } from '../src/stacks/backend-reset-guard.js'; +import type { LeasedDatabase } from '../src/stacks/backend-reset-guard.js'; +import { controlAppServer, controlBackendRuntime, parseRuntimeControlSpec, prepareRuntimeCrash } + from '../src/runtime/backend-control.js'; +import type { RuntimeControlSpec } from '../src/runtime/backend-control.js'; +import { leaseFromEnv } from '../src/runtime/backend-lease.js'; +import type { LeasedSpacetimeTarget } from '../src/runtime/spacetime-target.js'; + +import { STACK_BENCH_ROOT as ROOT } from '../src/package-root.js'; +import { captureResponses, ReceivedTransport } from './transport-frames.js'; +import type { ActionEvidence } from '../src/actions/action-contract.js'; +import type { CheckEvidence, CheckEvidenceAttachment, CheckEvidencePhase, + CheckEvidenceStatus } from '../src/evidence/check-evidence.js'; +import type { CompletedGradeFeatureResult, CompletedGradeReport, GradeCleanupFailure } + from '../src/evidence/grade-report.js'; +import type { CompiledFeature, CompiledScenarioDefinition, + CompiledStep } from '../src/composition/definition-compiler.js'; +import type { RecipeCheck, RecipeGradeRelease, RecipeRelease } from '../src/composition/recipe-release.js'; +import type { TrackAction } from '../src/composition/tracks.js'; + +type JsonRecord = Record; +type ActorWrite = { + url: string; + method: string; + headers: Record; + body: JsonRecord | null; +}; +type ActorWebSocketWrite = { event: unknown; body: JsonRecord }; +type ActorContextEntry = { context: BrowserContext; name: string; page: Page | null; traceStarted?: boolean }; +type CleanupBrowserContext = { + tracing: { stop(options: { path: string }): Promise }; + close(): Promise; +}; +type CleanupVideo = { saveAs(path: string): Promise; delete(): Promise }; +type CleanupPage = { video(): CleanupVideo | null }; +type CleanupActorContextEntry = { + traceStarted?: boolean; + context: CleanupBrowserContext; + name: string; + page: CleanupPage | null; +}; +type FeatureResult = Omit & { + setupEvidence?: CheckEvidence; +}; +type GradeArgs = { + url?: string; + level: number; + headed: boolean; + selectedCheckKeys: string[]; + out?: string; + label?: string; + feature?: number; + spec?: string; + restartSpec?: RuntimeControlSpec; + backend?: string; + track?: string; + recipe?: string; + expectedRecipeSha256?: string; + credentialAliases?: unknown; + selectionSha256?: string; + parentAttemptId?: string; + dbName?: string; + app?: string; + media?: string; + failureMedia?: string; + trace?: boolean; + nullControl: boolean; + diagnostic?: boolean; + savedDiagnostic?: ReturnType; + browserWsEndpoint?: string; +}; +type GradeRunContext = { + savedReader?: { path: string; sha256: string }; + checkoutActivity?: { unsettled: boolean }; + checkoutSnapshots?: ReturnType['checkoutSnapshots']; + actionCancellation?: { reason: string | null }; + runId: string; + roomName: (base: string) => string; + restartSpec?: RuntimeControlSpec; + url: string; + backend?: string; + actions: TrackAction[]; + spacetime: LeasedSpacetimeTarget | null; + dbName?: string; + databaseLease?: LeasedDatabase | null; + appDir?: string; + scope?: string; + extraContexts?: ActorContextEntry[]; + recorded?: Record; + unverified?: string[]; + verified?: string[]; + actionEvidence?: Array<{ actor: string | null; evidence: ActionEvidence }>; + serverCheck?: string | null; + lastCalls?: ConcurrentCallResult | null; + defaultWithin?: number; + nullControl: boolean; + // True while a scenario step has stopped the application server and no + // later step or restore has started it again. + applicationStopped?: boolean; +}; +type ActionFailure = Error & { actionEvidence?: ActionEvidence; actionActor?: string | null }; +const APPLICATION_RESTORE_SETTLE_MS = 8000; +const APPLICATION_RESTORE_TIMEOUT_MS = 60_000; +class ApplicationNotRestored extends Error { + constructor(reason: string) { + super(`the application server stopped by the harness was not restored: ${reason}`); + } +} +type CheckFailure = { + status: CheckEvidenceStatus; + code: string; + actor: string | null; + summary: string | null; + finding: Finding | null; + observation: unknown; + expected: unknown; + retryable: boolean; +}; + +function errorMessage(error: unknown): string { + return error instanceof Error ? error.message : String(error); +} + +function actionFailure(error: unknown): ActionFailure | null { + return error instanceof Error ? error as ActionFailure : null; +} +// The sentence the coding agent was given for this behaviour travels with the +// grade, so a repair report can repeat it instead of describing the check. +const authored = (criterion: { statedBy?: string }): { statedBy?: string } => + criterion.statedBy ? { statedBy: criterion.statedBy } : {}; +const DEFAULT_WITHIN = 5000; +const SETUP_WITHIN = 20000; +// Keep the cause when Playwright prefixes it with locator retry details. +function keepReason(detail: unknown, limit = 600): string { + const s = String(detail ?? ''); + if (s.length <= limit) return s; + const [head, ...rest] = s.split('\n'); + const reasons = rest + .map(l => l.trim()) + .filter(l => /^-\s/.test(l)) + .map(l => l.replace(/^-\s*/, '')) + .filter(l => !/^(waiting for|retrying|attempting|scrolling|done scrolling|locator resolved to|\d+ ×)/i.test(l)); + const kept = [...new Set(reasons)].slice(0, 4); + const out = kept.length ? `${head}\n - ${kept.join('\n - ')}` : s.slice(0, limit); + return out.length > limit ? out.slice(0, limit) : out; +} + +export function parseGradeArgs(argv: readonly string[]): GradeArgs { + const { values } = parseNodeArgs({ args: [...argv.slice(2)], options: { + url: { type: 'string' }, level: { type: 'string' }, out: { type: 'string' }, + label: { type: 'string' }, feature: { type: 'string' }, spec: { type: 'string' }, + 'restart-spec': { type: 'string' }, backend: { type: 'string' }, track: { type: 'string' }, + recipe: { type: 'string' }, 'expected-recipe-sha256': { type: 'string' }, + 'selected-check': { type: 'string', multiple: true }, + 'credential-aliases-json': { type: 'string' }, 'selection-sha256': { type: 'string' }, + 'parent-attempt-id': { type: 'string' }, 'db-name': { type: 'string' }, + app: { type: 'string' }, media: { type: 'string' }, 'failure-media': { type: 'string' }, + trace: { type: 'boolean' }, headed: { type: 'boolean' }, + 'null-control': { type: 'boolean' }, + diagnostic: { type: 'boolean' }, + 'saved-diagnostic': { type: 'string' }, + 'browser-ws-endpoint': { type: 'string' }, + } }); + const args: GradeArgs = { url: values.url, level: values.level === undefined ? 1 : Number(values.level), + out: values.out, label: values.label, + feature: values.feature === undefined ? undefined : Number(values.feature), spec: values.spec, + restartSpec: values['restart-spec'] === undefined ? undefined + : parseRuntimeControlSpec(JSON.parse(values['restart-spec'])), + backend: values.backend, track: values.track, recipe: values.recipe, + expectedRecipeSha256: values['expected-recipe-sha256'], + selectedCheckKeys: values['selected-check'] ?? [], + credentialAliases: values['credential-aliases-json'] === undefined + ? undefined : JSON.parse(values['credential-aliases-json']), + selectionSha256: values['selection-sha256'], parentAttemptId: values['parent-attempt-id'], + dbName: values['db-name'], app: values.app, media: values.media, + failureMedia: values['failure-media'], trace: values.trace, headed: values.headed ?? false, + nullControl: values['null-control'] ?? false, + diagnostic: values.diagnostic ?? false, + browserWsEndpoint: values['browser-ws-endpoint'] }; + if (!args.url || !args.spec) { + throw new Error('Usage: node dist/grader/grade.js --url --spec ' + + '--level [--out ] [--label ] [--feature ]'); + } + if (args.diagnostic && (args.recipe || args.expectedRecipeSha256 || args.selectedCheckKeys.length)) { + throw new Error('diagnostic grades cannot select a scored recipe or check catalog'); + } + if (values['saved-diagnostic']) { + if (!args.diagnostic) throw new Error('saved readers require zero-point diagnostics'); + args.savedDiagnostic = inspectSavedDiagnostic(JSON.parse(values['saved-diagnostic']), process.cwd()); + if (args.backend !== args.savedDiagnostic.backend) throw new Error('saved diagnostic backend mismatch'); + } + let url: URL; + try { url = new URL(args.url); } + catch { throw new Error('--url must be a valid HTTP or HTTPS URL'); } + if (url.protocol !== 'http:' && url.protocol !== 'https:') { + throw new Error('--url must use HTTP or HTTPS'); + } + if (!Number.isInteger(args.level) || args.level < 1) { + throw new Error('--level must be a positive integer'); + } + if (args.feature !== undefined && (!Number.isInteger(args.feature) || args.feature < 1)) { + throw new Error('--feature must be a positive integer'); + } + if (args.selectionSha256 && !/^[a-f0-9]{64}$/.test(args.selectionSha256)) { + throw new Error('--selection-sha256 must be 64 lowercase hexadecimal characters'); + } + if (args.browserWsEndpoint) { + let endpoint: URL; + try { endpoint = new URL(args.browserWsEndpoint); } + catch { throw new Error('--browser-ws-endpoint must be a valid WebSocket URL'); } + if (!['ws:', 'wss:'].includes(endpoint.protocol)) { + throw new Error('--browser-ws-endpoint must use ws or wss'); + } + } + return args; +} + +const tid = stableElementSelector; +const uniq = () => randomUUID().slice(0, 16); +const MAX_CONSOLE_ERRORS = 200; + +// Isolated browser actor + +// Which requests count as writes worth capturing for replay and forgery. The +// default covers chat's routes; a scenario spec can widen it for an application +// whose endpoints are named differently (`writeUrlPattern`). +const DEFAULT_WRITE_URL = '\\/api\\/|\\/rooms|\\/messages'; +let WRITE_URL_RE = new RegExp(DEFAULT_WRITE_URL); + + +export class Actor { + readonly name: string; + readonly context: BrowserContext; + page!: Page; + readonly consoleErrors: string[]; + private readonly transport = new ReceivedTransport(); + readonly ready: Promise; + get received(): readonly string[] { return this.transport.chunks; } + lastWrite: ActorWrite | null = null; + lastWrites: Record = {}; + writes: ActorWrite[] = []; + lastWsWrite: ActorWebSocketWrite | null = null; + annotate = false; + + constructor(name: string, page: Page, context: BrowserContext) { + this.name = name; + this.context = context; + this.consoleErrors = []; + // Test privacy against delivered payloads, not rendered content. + this.ready = this.attach(page); + } + async attach(page: Page): Promise { + this.page = page; + // Capture writes so checks can replay them with changed fields or actors. + this.lastWrite = null; + this.lastWrites = {}; + this.writes = []; + this.lastWsWrite = null; + page.on('dialog', dialog => { + void dialog.dismiss().catch(error => { + if (page.isClosed()) return; + this.consoleErrors.push(`dialog dismiss failed: ${errorMessage(error)}`); + if (this.consoleErrors.length > MAX_CONSOLE_ERRORS) this.consoleErrors.shift(); + }); + }); + // Capture wire data separately from what the application renders. + page.on('websocket', ws => { + ws.on('framesent', f => { + const p = typeof f.payload === 'string' ? f.payload : ''; + const m = p.match(/^\d+(\[.*\])$/s); + if (!m) return; + try { + const [event, arg] = JSON.parse(m[1] as string) as unknown[]; + if (arg && typeof arg === 'object' && !Array.isArray(arg)) { + this.lastWsWrite = { event, body: arg as JsonRecord }; + } + } catch { /* not a socket.io event frame */ } + }); + // Binary frames are decoded as UTF-8 too, after any SpacetimeDB frame + // compression: a binary wire format still carries message text as + // inline UTF-8 bytes, so a substring search finds it without the + // harness knowing the encoding. + ws.on('framereceived', f => this.record(f.payload)); + }); + page.on('request', req => { + if (req.method() === 'GET' || req.method() === 'OPTIONS') return; + const url = req.url(); + if (!WRITE_URL_RE.test(url)) return; + let body: JsonRecord | null = null; + try { + const candidate: unknown = JSON.parse(req.postData() ?? ''); + if (candidate && typeof candidate === 'object' && !Array.isArray(candidate)) { + body = candidate as JsonRecord; + } + } catch { /* bodyless, e.g. a DELETE */ } + // Forging needs a body to tamper with; replaying does not — a privileged + // action is often a bare DELETE whose meaning is entirely in the URL. + const write = { url, method: req.method(), headers: req.headers(), body }; + this.writes.push(write); + if (this.writes.length > 200) this.writes.shift(); + if (body && typeof body === 'object') { + this.lastWrite = write; + this.lastWrites[req.method()] = write; + } + }); + page.on('console', m => { + if (m.type() !== 'error') return; + const text = m.text(); + // Expected 4xx responses are not application console failures. + if (/Failed to load resource.*status of 4\d\d/.test(text)) return; + this.consoleErrors.push(text.slice(0, 200)); + if (this.consoleErrors.length > MAX_CONSOLE_ERRORS) this.consoleErrors.shift(); + }); + page.on('pageerror', e => { + this.consoleErrors.push(`pageerror: ${e.message.slice(0, 200)}`); + if (this.consoleErrors.length > MAX_CONSOLE_ERRORS) this.consoleErrors.shift(); + }); + await captureResponses(page, this.transport); + } + record(payload: string | Buffer): void { + this.transport.record(payload); + } + wasSent(needle: string, requireComplete = true): boolean { + return this.transport.contains(needle, requireComplete); + } + loc(testid: string, { contains, scope }: + { contains?: string; scope?: { testid: string; contains?: string } } = {}) { + // `scope` narrows the search to inside a specific container (e.g. the badge + // belonging to ONE room), so a stale element elsewhere can't satisfy it. + const root = scope + ? this.page.locator(tid(scope.testid), { hasText: scope.contains }).filter({ visible: true }).first() + : this.page; + const selector = tid(testid); + return (contains + ? root.locator(selector, { hasText: contains }) + : root.locator(selector)).filter({ visible: true }).first(); + } +} + +// Expand scenario aliases to the run-scoped values used by the app. +const expand = (s: unknown, ctx: GradeRunContext): unknown => + typeof s === 'string' + ? s.replace(/\{room:([^}]+)\}/g, (_, b) => ctx.roomName(b)) + // Keep generated usernames alphanumeric so ordinary validators accept them. + .replace(/\{user:([^}]+)\}/g, (_, n) => `${n}${ctx.scope}`) + : s; + + +// Put test context in recordings without exposing it to scoped app selectors. + +const OVERLAY_ID = '__stackbench_overlay'; + +async function annotate(actor: Actor | undefined, { feature, criterion, step, status }: + { feature?: string; criterion?: string; step?: string; status?: 'fail' | 'pass' } = {}): Promise { + if (!actor?.annotate) return; + await actor.page.evaluate(({ id, feature, criterion, step, status, who }) => { + let el = document.getElementById(id); + if (!el) { + el = document.createElement('div'); + el.id = id; + el.style.cssText = [ + 'position:fixed', 'inset:0 0 auto 0', 'z-index:2147483647', + 'font:12px/1.5 ui-monospace,SFMono-Regular,Menlo,monospace', + 'padding:6px 10px', 'pointer-events:none', 'white-space:pre', + 'background:rgba(12,12,16,.92)', 'color:#e8e8ef', + 'border-bottom:2px solid #4c8dff', + ].join(';'); + document.documentElement.appendChild(el); + } + const colour = status === 'fail' ? '#ff5c5c' : status === 'pass' ? '#3ddc84' : '#4c8dff'; + el.style.borderBottomColor = colour; + el.textContent = [ + `${who} ${feature ?? ''}`, + criterion ? ` ${status === 'fail' ? 'FAILED' : 'checking'}: ${criterion}` : '', + step ? ` > ${step}` : '', + ].filter(Boolean).join(String.fromCharCode(10)); + }, { id: OVERLAY_ID, feature, criterion, step, status, who: actor.name }).catch(() => {}); +} + +// Step execution + +function abortableSleep(ms: number, signal: AbortSignal | null = null): Promise { + if (signal?.aborted) return Promise.reject(signal.reason ?? new Error('action cancelled')); + return new Promise((resolve, reject) => { + const timer = setTimeout(done, ms); + function done() { + signal?.removeEventListener('abort', cancelled); + resolve(); + } + function cancelled() { + clearTimeout(timer); + signal?.removeEventListener('abort', cancelled); + reject(signal?.reason ?? new Error('action cancelled')); + } + signal?.addEventListener('abort', cancelled, { once: true }); + }); +} + +function browserActionCapabilities(actors: Map, ctx: GradeRunContext): Readonly> { + const defaultWithin = ctx.defaultWithin ?? DEFAULT_WITHIN; + const actorAccess = Object.freeze({ get: (name: string) => actors.get(name) }); + const runtimeValues = Object.freeze({ + applicationUrl: ctx.url, + defaultWithin, + expand: (value: unknown) => expand(value, ctx), + hyphenatedScopedUser: (name: string) => `${name}-${ctx.scope}`, + roomName: (base: string) => ctx.roomName(base), + scopedUser: (name: string) => `${name}${ctx.scope}`, + recorded: Object.freeze({ + get: (key: string) => ctx.recorded?.[key], + set: (key: string, value: unknown) => { (ctx.recorded ??= {})[key] = value; }, + }), + sleep: abortableSleep, + testId: tid, + clients: Object.freeze({ + async open(actor: Actor, settleMs: number, signal: AbortSignal) { + const fresh = await actor.context.newPage(); + fresh.setDefaultTimeout(defaultWithin); + await actor.attach(fresh); + await runApplicationNavigation(() => fresh.goto(ctx.url, { waitUntil: 'domcontentloaded', timeout: 20000 })); + await abortableSleep(settleMs, signal); + }, + async fresh(actor: Actor, sourceName: string, preserveStorage: boolean) { + const browser = actor.page.context().browser(); + if (!browser) throw new Error('actor browser is unavailable'); + const context = await browser.newContext(preserveStorage + ? { storageState: await actor.context.storageState({ indexedDB: true }) } + : undefined); + const name = `${sourceName}-fresh`; + // Own cleanup before page creation or navigation can fail. + const entry: ActorContextEntry = { context, name, page: null }; + ctx.extraContexts?.push(entry); + const fresh = await context.newPage(); + entry.page = fresh; + fresh.setDefaultTimeout(defaultWithin); + const observer = new Actor(`${actor.name}-fresh`, fresh, context); + await observer.ready; + // storageState omits sessionStorage. Seed the first document only; + // later reloads must retain the application's own storage changes. + const session = preserveStorage ? await context.newCDPSession(fresh) : null; + let seed: string | undefined; + try { + if (session) { + await session.send('Page.enable'); + const state = await actor.page.evaluate(() => ({ + origin: location.origin, entries: Object.entries(sessionStorage), + })); + const script = await session.send('Page.addScriptToEvaluateOnNewDocument', { + source: `if (window === window.top && location.origin === ${JSON.stringify(state.origin)}) { + for (const [key, value] of ${JSON.stringify(state.entries)}) sessionStorage.setItem(key, value); + }`, + }); + seed = script.identifier; + } + await runApplicationNavigation(() => fresh.goto(ctx.url, { waitUntil: 'domcontentloaded', timeout: 20000 })); + } finally { + if (session) { + try { if (seed) await session.send('Page.removeScriptToEvaluateOnNewDocument', { identifier: seed }); } + finally { await session.detach(); } + } + } + observer.annotate = actor.annotate; + actors.set(name, observer); + return name; + }, + }), + }); + const transportObservation = Object.freeze({ + defaultWithin, + expand: (value: unknown) => expand(value, ctx), + sleep: abortableSleep, + verification: Object.freeze({ + structural(message: string) { + ctx.verified?.push(message); + ctx.serverCheck = ctx.serverCheck ?? 'structural'; + }, + unverified(message: string) { + (ctx.unverified ??= []).push(message); + ctx.serverCheck = 'unverified'; + }, + verified(message: string) { + ctx.verified?.push(message); + ctx.serverCheck = 'verified'; + }, + }), + }); + const namedActions = createNamedActionsCapability({ + actions: ctx.actions, + backend: ctx.backend!, + url: ctx.url, + spacetime: ctx.spacetime, + lastCalls: Object.freeze({ + get: () => ctx.lastCalls ?? null, + set: value => { ctx.lastCalls = value; }, + }), + sleep: abortableSleep, + }); + const concurrency = Object.freeze({ + defaultWithin, + dispatch: (step: CompiledStep, signal: AbortSignal) => runRegisteredAction(step, actors, ctx, signal), + expand: (value: unknown) => expand(value, ctx), + sleep: abortableSleep, + testId: tid, + }); + return Object.freeze({ + actors: actorAccess, + 'application-files': Object.freeze({ root: ctx.appDir ?? null, expand: (value: unknown) => expand(value, ctx) }), + 'application-lifecycle': applicationLifecycle(ctx), + 'backend-lifecycle': createLifecycleCapability({ + restartSpec: ctx.restartSpec, + target: 'backend-runtime', + control: controlBackendRuntime, + sleep: abortableSleep, + }), + 'browser-interaction': runtimeValues, + 'browser-observation': runtimeValues, + clock: Object.freeze({ sleep: abortableSleep }), + concurrency, + 'database-read': createDatabaseReadCapability({ + savedReader: ctx.savedReader, + checkoutSnapshots: ctx.checkoutSnapshots ??= new Map(), + checkoutActivity: ctx.checkoutActivity ??= { unsettled: false }, + app: ctx.appDir, + backend: ctx.backend, + spacetime: ctx.spacetime, + databaseLease: ctx.databaseLease, + skip: ctx.nullControl, + expand: (value: string) => String(expand(value, ctx)), + }), + 'database-write': createDatabaseWriteCapability({ + backend: ctx.backend, + spacetime: ctx.spacetime, + databaseLease: ctx.databaseLease, + skip: ctx.nullControl, + expand: (value: string) => String(expand(value, ctx)), + }), + 'named-actions': namedActions, + 'process-crash': Object.freeze({ combinedBoundary: !ctx.nullControl && ctx.restartSpec?.backend === 'spacetime', + prepare: (target: 'application' | 'database') => { + if (!ctx.restartSpec || ctx.nullControl) throw new Error('process crash requires an owned grading runtime'); + return prepareRuntimeCrash(ctx.restartSpec, target); + } }), + subprocess: Object.freeze({ sleep: abortableSleep }), + 'transport-observation': transportObservation, + }); +} + +function applicationLifecycle(ctx: GradeRunContext) { + return createLifecycleCapability({ + restartSpec: ctx.restartSpec, + target: 'app-server', + control: controlAppServer, + sleep: abortableSleep, + onOperated: mode => { ctx.applicationStopped = mode === 'stop'; }, + }); +} + +async function runRegisteredAction(step: CompiledStep, actors: Map, ctx: GradeRunContext, + signal: AbortSignal | null = null): Promise { + if (ctx.actionCancellation?.reason) throw new Error(ctx.actionCancellation.reason); + const actionEvidence = await executeAction(ACTION_REGISTRY, step.do, step, + { + capabilities: browserActionCapabilities(actors, ctx), + signal, + // Closing this grader's connection cancels pending Playwright calls before + // the action executor drains them. It does not stop the app or its database. + onAbort: ACTION_REGISTRY.get(step.do).capabilities.includes('actors') + ? async () => { + if (ctx.actionCancellation) ctx.actionCancellation.reason = 'browser session cancelled; no further actions are permitted'; + const browsers = new Set([...actors.values()].map(actor => actor.page.context().browser())); + await Promise.all([...browsers].map(browser => browser?.close())); + } : undefined, + }); + ctx.actionEvidence?.push({ actor: step.actor ?? null, evidence: actionEvidence }); + if (actionEvidence.status === 'passed') return actionEvidence.observation; + const error = new Error(actionEvidence.summary ?? `${step.do} did not complete`); + Object.defineProperty(error, 'actionEvidence', { value: actionEvidence }); + Object.defineProperty(error, 'actionActor', { value: step.actor ?? null }); + throw error; +} + +function classifyCheckFailure(error: unknown, fallbackActor: string | null = null): CheckFailure { + const actionError = actionFailure(error); + const actionEvidence = actionError?.actionEvidence; + if (actionEvidence) { + return { + status: actionEvidence.status, + code: actionEvidence.code, + actor: actionError?.actionActor ?? fallbackActor, + summary: actionEvidence.summary ?? `${actionEvidence.action.id} did not complete`, + finding: actionEvidence.finding, + observation: actionEvidence.observation, + expected: actionEvidence.expected, + retryable: actionEvidence.retryable, + }; + } + if (error instanceof ApplicationNotRestored) { + return { status: 'harness_failure', code: 'application_not_restored', actor: fallbackActor, + summary: error.message, finding: null, observation: null, expected: null, retryable: false }; + } + const processFailure = harnessProcessFailure(error); + if (processFailure) return { status: 'harness_failure', code: 'process_failure', actor: fallbackActor, + summary: processFailure, finding: null, observation: null, expected: null, retryable: false }; + const browserFailure = harnessBrowserFailure(error); + if (browserFailure) return { status: 'harness_failure', code: 'browser_failure', actor: fallbackActor, + summary: browserFailure, finding: null, observation: null, expected: null, retryable: false }; + if (error instanceof ActionApplicationFailure || error instanceof ActionInconclusive) { + return { status: error instanceof ActionInconclusive ? 'inconclusive' : 'failed', + code: error.classification, actor: fallbackActor, + summary: error.message, finding: isFinding(error.details.finding) ? error.details.finding : null, + observation: error.details.observation ?? null, + expected: error.details.expected ?? null, retryable: false }; + } + return { status: 'harness_failure', code: 'unclassified_exception', actor: fallbackActor, + summary: errorMessage(error ?? 'unknown grader failure'), + finding: null, observation: null, expected: null, retryable: false }; +} + +function buildCheckEvidence({ ctx, phase, startedAtMs, failure = null, actor = null, summary = null, + attachments = [], actions = ctx.actionEvidence ?? [], sensitivity = null }: { + ctx: GradeRunContext; phase: CheckEvidencePhase; startedAtMs: number; failure?: unknown; + actor?: string | null; summary?: string | null; attachments?: Array; + actions?: Array<{ actor: string | null; evidence: ActionEvidence }>; + sensitivity?: readonly string[] | null; + }): CheckEvidence { + const classified: CheckFailure = failure ? classifyCheckFailure(failure, actor) : { + status: 'passed', code: 'completed', actor: null, summary: null, finding: null, + observation: null, expected: null, retryable: false, + }; + const completedAtMs = Math.max(startedAtMs, evidenceNowMs()); + const evidenceSummary = summary ?? classified.summary; + return createCheckEvidence({ + ...classified, + phase, + summary: evidenceSummary == null ? null : keepReason(evidenceSummary), + startedAtMs, + completedAtMs, + actions, + attachments: attachments.map(attachment => typeof attachment === 'string' + ? { kind: 'screenshot', ref: basename(attachment) } : attachment), + sensitivity: sensitivity ?? actions.flatMap(entry => entry.evidence?.sensitivity ?? []), + }); +} + +async function runStep(step: CompiledStep, actors: Map, ctx: GradeRunContext): Promise { + return runRegisteredAction(step, actors, ctx); +} + +export async function closeActorContexts(entries: readonly CleanupActorContextEntry[], { + trace = false, media = null, slug = 'grade', +}: { trace?: boolean; media?: string | null; slug?: string } = {}): Promise { + const failures: GradeCleanupFailure[] = []; + const record = (name: string, stage: string, error: unknown): void => { failures.push({ + actor: name, + stage, + reason: keepReason(errorMessage(error)), + }); }; + for (const { context, name, page, traceStarted } of entries) { + if (trace && traceStarted) { + try { + await context.tracing.stop({ path: join(media ?? '.', `${slug}-${name}.trace.zip`) }); + } catch (error) { record(name, 'trace', error); } + } + let video = null; + if (media && page) { + try { video = page.video(); } + catch (error) { record(name, 'video-handle', error); } + } + try { await context.close(); } + catch (error) { record(name, 'context-close', error); } + if (video) { + try { await video.saveAs(join(media!, `${slug}-${name}.webm`)); } + catch (error) { record(name, 'video-save', error); } + try { await video.delete(); } + catch (error) { record(name, 'video-delete', error); } + } + } + return failures; +} + +// Feature grading + +function completedFeatureResult(result: FeatureResult): CompletedGradeFeatureResult { + if (!result.setupEvidence) { + throw new Error(`feature ${result.id} completed without setup evidence`); + } + return { ...result, setupEvidence: result.setupEvidence }; +} + +export async function gradeFeature(browser: Browser, feature: CompiledFeature, args: GradeArgs, + runCtx: GradeRunContext): Promise { + // Features share the app's DATABASE even though each gets fresh browser + // contexts, so user and room names are scoped per feature — otherwise a + // defect in one feature (e.g. a hijacked account) corrupts later setups. + const scope = `${runCtx.runId}f${feature.id}`; + runCtx.checkoutActivity ??= { unsettled: false }; + const extraContexts: ActorContextEntry[] = []; + const ctx: GradeRunContext = { ...runCtx, scope, roomName: (base: string) => `${base}-${scope}`, extraContexts, recorded: {}, checkoutSnapshots: new Map(), + unverified: [], verified: [], actionEvidence: [] }; + const actors = new Map(); + const contexts: ActorContextEntry[] = []; + const slug = `${args.label ?? 'run'}-f${feature.id}`; + + // A feature is worth what its criteria are worth. An explicit `max` is only + // a consistency check enforced by check-scenarios, never a top-up. + const featureMax = feature.criteria.reduce((n, c) => n + (c.points ?? 1), 0); + const result: FeatureResult = { + id: feature.id, name: feature.name, score: 0, max: featureMax, + criteria: [], consoleErrors: [], + }; + const restoreFailures: GradeCleanupFailure[] = []; + const closeAll = async () => { + // The abort hook already closed this connection, or reported that closure + // could not be confirmed. Do not hang again while collecting browser media. + if (ctx.actionCancellation?.reason) { + const failures = [{ actor: null, stage: 'browser-cancel', reason: ctx.actionCancellation.reason }]; + result.cleanupEvidence = { status: 'harness_failure', failures }; + return failures; + } + const failures = [...restoreFailures, ...await closeActorContexts([...contexts, ...extraContexts], { + trace: args.trace, media: args.media, slug, + })]; + if (failures.length) result.cleanupEvidence = { status: 'harness_failure', failures }; + return failures; + }; + // A criterion that stops the application server owns it only for its own + // steps. Whatever the outcome, the server is running again before the next + // criterion; a restore the harness cannot complete is the harness's failure + // and every later criterion in the feature is unmeasured, not failed. + const restoreApplicationServer = async () => { + if (!ctx.applicationStopped || restoreFailures.length) return; + try { + await applicationLifecycle(ctx) + .operate('start', APPLICATION_RESTORE_SETTLE_MS, AbortSignal.timeout(APPLICATION_RESTORE_TIMEOUT_MS)); + } catch (error) { + restoreFailures.push({ actor: null, stage: 'application-restore', + reason: keepReason(errorMessage(error)) }); + } + }; + const initializationStartedAtMs = evidenceNowMs(); + try { + if (ctx.actionCancellation?.reason) throw new Error(ctx.actionCancellation.reason); + for (const name of feature.actors!) { + // Isolated storage per actor. Video is per-context, so each actor gets its + // own recording — you can watch what every participant saw, side by side. + const context = await runBrowserInfrastructureOperation('context creation', () => + browser.newContext( + args.media ? { recordVideo: { dir: args.media, size: { width: 1280, height: 800 } } } : {} + )); + contexts.push({ context, name, page: null }); + if (args.trace) { + await runBrowserInfrastructureOperation('trace start', () => + context.tracing.start({ screenshots: true, snapshots: true })); + contexts[contexts.length - 1]!.traceStarted = true; + } + const page = await runBrowserInfrastructureOperation('page creation', () => context.newPage()); + contexts[contexts.length - 1]!.page = page; + page.setDefaultTimeout(SETUP_WITHIN); + const actor = new Actor(name, page, context); + await actor.ready; + actor.annotate = Boolean(args.media); + actors.set(name, actor); + const pending = new Map(); + const requested = (request: Request) => { + if (pending.size >= 20) return; + try { + const url = new URL(request.url()); + const origin = ['http:', 'https:'].includes(url.protocol) ? url.origin : url.protocol; + pending.set(request, `${request.resourceType()} ${origin.slice(0, 200)}`); + } catch { /* malformed URLs provide no safe origin */ } + }; + const completed = (request: Request) => { pending.delete(request); }; + page.on('request', requested); + page.on('requestfinished', completed); + page.on('requestfailed', completed); + try { + await runApplicationNavigation(() => page.goto(args.url!, { waitUntil: 'domcontentloaded', timeout: 20000 })); + } catch (cause) { + for (const resource of pending.values()) { + result.consoleErrors.push(`[${name}] Navigation pending resource (up to 20): ${resource}`); + } + throw cause; + } finally { + page.off('request', requested); + page.off('requestfinished', completed); + page.off('requestfailed', completed); + } + } + } catch (error) { + const classified = classifyCheckFailure(error); + for (const actor of actors.values()) { + for (const message of actor.consoleErrors) { + result.consoleErrors.push(`[${actor.name}] ${sanitiseConsoleError(message)}`); + } + } + const reason = keepReason((classified.summary ?? '').trim()); + result.setupEvidence = buildCheckEvidence({ ctx, phase: 'setup', startedAtMs: initializationStartedAtMs, + failure: error, summary: reason }); + for (const criterion of feature.criteria) { + const points = criterion.points ?? 1; + const evidence = buildCheckEvidence({ ctx, phase: 'setup', startedAtMs: initializationStartedAtMs, + failure: error, summary: `browser setup failed: ${reason}`, actions: [] }); + if (evidence.status === 'failed') evidence.status = 'blocked'; + result.criteria.push({ id: criterion.id, desc: criterion.desc, points, evidence, + ...authored(criterion) }); + if (!evidenceIsMeasured(evidence)) result.inconclusive = [...(result.inconclusive ?? []), + { id: criterion.id, points, status: evidence.status, code: evidence.code, + phase: evidence.phase, summary: evidence.summary }]; + } + await closeAll(); + return completedFeatureResult(result); + } + + const captureFailureScreenshots = async (label: string): Promise => { + if (ctx.actionCancellation?.reason || !args.failureMedia) return []; + mkdirSync(args.failureMedia, { recursive: true }); + const captured: string[] = []; + for (const { name, page } of [...contexts, ...extraContexts]) { + if (!page) continue; + const path = join(args.failureMedia, `${slug}-${label}-${name}.png`); + const ok = await page.screenshot({ path, fullPage: true, timeout: 5000 }) + .then(() => true, () => false); + if (ok) captured.push(path); + } + return captured; + }; + + const setupStartedAtMs = evidenceNowMs(); + ctx.defaultWithin = SETUP_WITHIN; + ctx.actionEvidence = []; + try { + // Setup is not scored, but a failure makes the feature untestable (0). + for (const step of feature.setup) { + if (ctx.actionCancellation?.reason) throw new Error(ctx.actionCancellation.reason); + await annotate(actors.get(step.actor), { feature: feature.name, criterion: 'setup', step: step.do }); + await runStep(step, actors, ctx); + } + } catch (err) { + // Preserve the typed setup failure on every affected criterion. + const classified = classifyCheckFailure(err); + const why = keepReason((classified.summary ?? '').trim()); + const screenshots = await captureFailureScreenshots('setup'); + result.setupEvidence = buildCheckEvidence({ ctx, phase: 'setup', startedAtMs: setupStartedAtMs, + failure: err, summary: why, attachments: screenshots }); + for (const c of feature.criteria) { + const base = why ? `Blocked by a failed prerequisite: ${why}` : 'Blocked by a failed prerequisite'; + const points = c.points ?? 1; + const evidence = buildCheckEvidence({ ctx, phase: 'setup', startedAtMs: setupStartedAtMs, + failure: err, summary: base, actions: [], sensitivity: result.setupEvidence.sensitivity, + attachments: [{ kind: 'check-evidence', ref: 'feature.setupEvidence' }, ...screenshots] }); + if (evidence.status === 'failed') evidence.status = 'blocked'; + const recorded = { id: c.id, desc: c.desc, points, evidence, ...authored(c) }; + result.criteria.push(recorded); + if (!evidenceIsMeasured(evidence)) { + result.inconclusive = [...(result.inconclusive ?? []), + { id: c.id, points, status: evidence.status, code: evidence.code, + phase: evidence.phase, summary: evidence.summary }]; + } + } + if (screenshots.length) result.screenshots = screenshots; + await closeAll(); + return completedFeatureResult(result); + } + result.setupEvidence = buildCheckEvidence({ ctx, phase: 'setup', startedAtMs: setupStartedAtMs }); + ctx.defaultWithin = DEFAULT_WITHIN; + for (const actor of actors.values()) actor.page.setDefaultTimeout(DEFAULT_WITHIN); + + for (const criterion of feature.criteria) { + let failure: unknown = null, detail: string | null = null, activeActor: string | null = null; + let criterionScreenshots: string[] = []; + const criterionStartedAtMs = evidenceNowMs(); + ctx.actionEvidence = []; + ctx.serverCheck = null; + try { + if (restoreFailures.length) throw new ApplicationNotRestored(restoreFailures[0]!.reason); + for (const step of criterion.steps) { + if (ctx.actionCancellation?.reason) throw new Error(ctx.actionCancellation.reason); + activeActor = step.actor ?? activeActor; + await annotate(actors.get(step.actor) ?? actors.values().next().value, + { feature: feature.name, criterion: criterion.id, step: step.do }); + await runStep(step, actors, ctx); + } + for (const a of actors.values()) { + if (ctx.actionCancellation?.reason) throw new Error(ctx.actionCancellation.reason); + await annotate(a, { feature: feature.name, criterion: criterion.id, step: 'passed', status: 'pass' }); + } + } catch (err) { + failure = err; + const classified = classifyCheckFailure(err, activeActor); + detail = classified.summary; + // captureFailureScreenshots also refuses a cancelled session. + if (!ctx.actionCancellation?.reason && args.media) { + for (const a of actors.values()) { + await annotate(a, { feature: feature.name, criterion: criterion.id, + step: errorMessage(err).slice(0, 120), status: 'fail' }); + } + const shotActor = actors.get(criterion.steps[criterion.steps.length - 1]?.actor) ?? actors.values().next().value; + const shot = join(args.media, `${slug}-${criterion.id}.png`); + const captured = await shotActor.page.screenshot({ path: shot, fullPage: true }) + .then(() => true, () => false); + if (captured) criterionScreenshots.push(shot); + } else { + criterionScreenshots = await captureFailureScreenshots(criterion.id); + } + if (criterionScreenshots.length) { + result.screenshots = [...(result.screenshots ?? []), ...criterionScreenshots]; + } + } + await restoreApplicationServer(); + const evidence = buildCheckEvidence({ ctx, phase: 'assertion', startedAtMs: criterionStartedAtMs, + failure, actor: activeActor, summary: detail, attachments: criterionScreenshots }); + result.criteria.push({ id: criterion.id, desc: criterion.desc, points: criterion.points, + evidence, ...authored(criterion), + ...(ctx.serverCheck ? { serverCheck: ctx.serverCheck } : {}) }); + if (evidencePassed(evidence)) result.score += criterion.points; + else if (!evidenceIsMeasured(evidence)) { + result.inconclusive = [...(result.inconclusive ?? []), + { id: criterion.id, points: criterion.points, status: evidence.status, code: evidence.code, + phase: evidence.phase, summary: evidence.summary }]; + } + } + + for (const actor of actors.values()) { + for (const e of actor.consoleErrors) result.consoleErrors.push(`[${actor.name}] ${e}`); + } + + // Retain diagnostics for server-side checks that could not execute. The + // action executor marks those criteria inconclusive, so they cannot score. + if (ctx.unverified?.length) result.unverified = ctx.unverified; + if (ctx.verified?.length) result.verified = ctx.verified; + + await closeAll(); + if (args.media) result.videos = contexts.map(c => join(args.media!, `${slug}-${c.name}.webm`)); + return completedFeatureResult(result); +} + +// Main + +export function gradeDatabaseLease(backend?: string, env: NodeJS.ProcessEnv = process.env): LeasedDatabase | null { + if ((backend !== 'mongodb' && backend !== 'postgres') + || !(env.STACK_BENCH_LEASE || env.STACK_BENCH_LEASE_TOKEN)) return null; + return requireLeasedDatabase(leaseFromEnv(env, { backend, active: true }).lease); +} + +async function main(): Promise { + const startedAt = new Date().toISOString(); + const args = parseGradeArgs(process.argv); + const specPath = args.spec!; + let spec: CompiledScenarioDefinition; + try { + const compiled = compileScenarioDefinition(JSON.parse(readFileSync(specPath, 'utf8')), + { source: specPath }); + spec = materializeScenarioCredentials(compiled, args.credentialAliases); + } catch (error) { + throw new Error(`cannot compile scenario ${specPath}: ${errorMessage(error)}`, { cause: error }); + } + + if (typeof spec.writeUrlPattern === 'string' && spec.writeUrlPattern) { + WRITE_URL_RE = new RegExp(spec.writeUrlPattern); + } + + const candidateFeatures = args.feature ? spec.features.filter(f => f.id === args.feature) : spec.features; + if (args.diagnostic && candidateFeatures.some(feature => feature.criteria.some(check => check.points !== 0))) { + throw new Error('diagnostic grades require zero-point checks'); + } + if (args.feature && candidateFeatures.length === 0) { + throw new Error(`scenario ${specPath} has no feature ${args.feature}`); + } + const runId = uniq(); + // Where the named actions live. The track declares their names; the + // authenticated backend lease—not generated application config—selects the + // SpacetimeDB host, module and exact build container used for direct SQL. + let actions: TrackAction[] = [], spacetime: LeasedSpacetimeTarget | null = null, + recipeRelease: RecipeGradeRelease | null = null, + recipeIdentityRelease: RecipeRelease | null = null, + calibration: ReturnType | null = null; + if (args.track) { + const track = loadTrack(args.track); + actions = track.actions; + const binding = args.diagnostic ? null : resolveGradeRecipeArtifactBinding(track, args.level, specPath, + args.feature ?? null, args.recipe); + recipeRelease = binding?.release ?? null; + recipeIdentityRelease = binding?.sourceRelease ?? null; + } + if (args.expectedRecipeSha256 + && recipeRelease?.contentSha256 !== args.expectedRecipeSha256) { + throw new Error(`recipe changed before grading: expected ${args.expectedRecipeSha256}, ` + + `resolved ${recipeRelease?.contentSha256 ?? 'no recipe'}`); + } + const selectedScenario = selectScenarioChecks( + { ...spec, features: candidateFeatures }, recipeRelease, args.selectedCheckKeys); + const features = selectedScenario.features; + const selectedChecks = selectedScenario.checks; + if (!features.length) throw new Error(`scenario ${specPath} has no selected checks`); + if (args.track) { + const track = loadTrack(args.track); + calibration = resolveCalibrationForRelease(recipeIdentityRelease, { + trackRoot: track.dir, + stackBenchRoot: ROOT, + alias: `L${args.level}`, + }); + } + spacetime = args.backend + ? STACK_ADAPTER_REGISTRY.get(args.backend).grading.context({ requireBuildContainer: true }) + : null; + const databaseLease = gradeDatabaseLease(args.backend); + + const ctx: GradeRunContext = { actionCancellation: { reason: null }, runId, roomName: (base: string) => `${base}-${runId}`, + restartSpec: args.restartSpec, url: args.url!, + backend: args.backend, actions, spacetime, dbName: args.dbName, + databaseLease, + nullControl: args.nullControl, + appDir: args.app, savedReader: args.savedDiagnostic?.reader }; + + const browser = args.browserWsEndpoint + ? await chromium.connect(args.browserWsEndpoint) + : await chromium.launch({ headless: !args.headed, ...attemptBrowserLaunchOptions() }); + const report: JsonRecord & CompletedGradeReport & { + inconclusive?: Array; + cleanupEvidence?: { status: 'harness_failure'; failures: GradeCleanupFailure[] }; + } = { + definitionSchemaVersion: spec.schemaVersion, + recipeRelease, + label: args.label ?? null, url: args.url, level: args.level, runId, + total: 0, max: features.reduce((n, f) => n + f.criteria.reduce((m, c) => m + (c.points ?? 1), 0), 0), features: [], + selection: recipeRelease ? { + ...(args.selectionSha256 ? { sha256: args.selectionSha256 } : {}), + checks: selectedChecks.map(({ stableKey, packId, checkGroupId, featureId, criterionId, + description, points }) => { + if (!packId) throw new Error(`selected check ${stableKey} has no pack id`); + return { stableKey, packId, checkGroupId, featureId, criterionId, description, points }; + }), + } : null, + }; + const checkByCriterion = new Map(selectedChecks.map(check => [ + `${String(check.featureId)}\0${String(check.criterionId)}`, check, + ])); + + try { + for (const feature of features) { + process.stdout.write(`Feature ${feature.id}: ${feature.name} ... `); + const r = await gradeFeature(browser, feature, args, ctx); + if (recipeRelease) { + for (const criterion of r.criteria) { + const check = checkByCriterion.get(`${String(feature.id)}\0${String(criterion.id)}`); + if (!check) throw new Error(`graded criterion ${feature.id}/${criterion.id} has no recipe check`); + criterion.stableKey = check.stableKey; + } + } + report.features.push(r); + report.total += r.score; + // The recipe owns the denominator. An unmeasured criterion earns zero and + // remains explicitly inconclusive; it must never change the contract. + if (r.inconclusive?.length) { + report.inconclusive = [...(report.inconclusive ?? []), + ...r.inconclusive.map(c => ({ feature: r.id, ...c }))]; + } + console.log(`${r.score}/${r.max}`); + for (const c of r.criteria.filter(c => !evidencePassed(c.evidence))) { + console.log(` ${renderEvidenceConsoleLine(c.evidence, c.id)}`); + } + } + } finally { + try { if (!ctx.actionCancellation?.reason) await browser.close(); } + catch (error) { + report.cleanupEvidence = { status: 'harness_failure', failures: [{ + actor: null, stage: 'browser-close', reason: keepReason(errorMessage(error)), + }] }; + } + } + + if (recipeRelease) report.packRuntime = measureGradePackRuntime(report); + + console.log(`\nTOTAL ${report.total}/${report.max}`); + if (args.out) { + const artifactId = `grade-${runId}`; + writeArtifact(args.out, { + kind: 'grade', + id: artifactId, + attempt: { id: artifactId, parentId: args.parentAttemptId ?? null }, + timestamps: { startedAt, completedAt: new Date().toISOString() }, + identities: recipeArtifactIdentities(recipeIdentityRelease, { + calibration: calibration ? { id: calibration.id, + sha256: calibration.contentSha256 } : null, + stackAdapter: args.backend ? { id: args.backend } : null, + }), + payload: report, + }); + console.log(`Report written to ${args.out}`); + } +} + +if (process.argv[1] && fileURLToPath(import.meta.url) === process.argv[1]) { + main().catch(error => { + console.error(error instanceof Error ? (error.stack ?? error.message) : String(error)); + process.exitCode = 2; + }); +} diff --git a/tools/stack-bench/grader/mutation-test.ts b/tools/stack-bench/grader/mutation-test.ts new file mode 100644 index 00000000000..a18a8589677 --- /dev/null +++ b/tools/stack-bench/grader/mutation-test.ts @@ -0,0 +1,850 @@ +#!/usr/bin/env node +// A valid mutation fails only its declared criterion against a passing baseline. +import { + copyFileSync, + existsSync, + mkdirSync, + mkdtempSync, + readFileSync, + unlinkSync, + writeFileSync, +} from "node:fs"; +import { createHash, randomUUID } from "node:crypto"; +import { dirname, join, relative, resolve, sep } from "node:path"; +import { fileURLToPath } from "node:url"; +import { execFileSync } from "node:child_process"; +import { parseArgs as parseNodeArgs } from "node:util"; +import { currentEngineIdentity, emptyArtifactIdentities, readArtifactPayload, + writeRunJson } from "../src/evidence/artifacts.js"; +import { controlAppServer, parseRuntimeControlSpec } from "../src/runtime/backend-control.js"; +import type { RuntimeControlSpec } from "../src/runtime/backend-control.js"; +import { leaseFromEnv } from '../src/runtime/backend-lease.js'; +import { inspectBuildContainer } from '../src/stacks/hosted-lifecycle.js'; +import { CODING_CONTAINER_APP_ROOT, codingContainerAgentCommand, codingContainerAgentExecOptions } + from '../src/runtime/coding-container-policy.js'; +import { + classifyMutationResult, + groupMutationsByScenario, + isRetryableMutationBaseline, + isRetryableMutationResult, + mutationFileEdits, + mutationTargetKeys, + readMutationManifest, + releaseScenarioCheckKeys, + resolveMutationScenarioPath, + reusableMutationBaseline, + resolveMutationFile, + validateMutationBaseline, + validateMutationDefinitions, +} from "../src/evidence/mutation-analysis.js"; +import { dbName, loadTrack, TRACK_MANIFEST_FILE } from "../src/composition/tracks.js"; +import { resolveRecipeRelease } from "../src/composition/recipe-release.js"; +import { resetBackend } from "../src/stacks/backend-reset.js"; +import { STACK_ADAPTER_REGISTRY } from "../src/stacks/stack-adapters.js"; +import { mutationShard } from "../src/evidence/mutation-shards.js"; +import { reusableMutationEvidence } from "../src/evidence/mutation-checkpoint.js"; +import { MUTATION_GRADE_MAX_TIMEOUT_MS, mutationGradeTimeoutMs } + from "../src/evidence/mutation-control.js"; +import { assertAppSourceIdentity } from "../src/runtime/source-snapshot.js"; +import type { TextCommandExecutor } from '../src/runtime/command-executor.js'; +import type { LoadedMutationManifest, MutationDefinition } from '../src/evidence/mutation-analysis.js'; +import { redactCredentials } from '../src/evidence/diagnostic-sanitizer.js'; +import type { MutationCheckpointBaseline, MutationCheckpointIdentity, + MutationCheckpointResult } from '../src/evidence/mutation-checkpoint.js'; + +type JsonRecord = Record; +type MutationSpec = LoadedMutationManifest; +type MutationArgs = { + app?: string; url?: string; mutations?: string; level?: string; spec?: string; backend?: string; + track?: string; recipe?: string; selectedCheckKeys?: string[]; dbName?: string; runIndex?: string; + restartSpec?: RuntimeControlSpec; out?: string; parentAttemptId?: string; + mutationShardIndex?: number; mutationShardCount?: number; resumeFrom?: string; checkpointOut?: string; + baselineBundle?: string; expectedCalibrationIdentity?: JsonRecord; maxRuntimeMinutes?: number; + imageId?: string; mutationAttemptId?: string; expectedRecipeSha256?: string; + reseedOnReset?: boolean; +}; +type ParsedMutationArgs = MutationArgs & { + app: string; + url: string; + mutations: string; + level: string; + recipe: string; + maxRuntimeMinutes: number; + mutationAttemptId: string; +}; +type GradeReport = { total?: unknown; max?: unknown; + features?: Array<{ id?: unknown; score?: unknown; + criteria?: Array<{ id?: string; stableKey?: unknown; evidence?: unknown }> }>; + [key: string]: unknown }; +type MutationResult = ReturnType & { id: string; scenario: string; targets: string[] }; +type BaselineEntry = MutationCheckpointBaseline & { total: unknown; max: unknown }; +type MutationFile = { target: string; backup: string; original: string; edits: ReturnType }; + +export function mutationFailureMessage(error: unknown): string { + return redactCredentials(error instanceof AggregateError + ? `${error.message}: ${error.errors.map(mutationFailureMessage).join('; ')}` + : errorMessage(error)); +} + +function errorMessage(error: unknown): string { + return error instanceof Error ? error.message : String(error); +} + +export function restoreMutationSource(file: { target: string; backup: string; original: string }): void { + // Restart hands files to the app UID. copyFileSync can fail chmod and unlink + // its destination even when the controller can write through group access. + writeFileSync(file.target, file.original); + if (readFileSync(file.target, 'utf8') !== file.original) { + throw new Error(`restore verification failed for ${file.target}`); + } + unlinkSync(file.backup); +} + +function jsonObject(value: unknown, label: string): JsonRecord { + if (value === null || typeof value !== 'object' || Array.isArray(value)) { + throw new Error(`${label} must be an object`); + } + return value as JsonRecord; +} + +const HERE = dirname(fileURLToPath(import.meta.url)); +const GRADER = join(HERE, "grade.js"); + +export function parseMutationArgs(argv: readonly string[]): ParsedMutationArgs { + const { values } = parseNodeArgs({ args: [...argv.slice(2)], options: { + app: { type: 'string' }, url: { type: 'string' }, mutations: { type: 'string' }, + level: { type: 'string' }, spec: { type: 'string' }, backend: { type: 'string' }, + track: { type: 'string' }, recipe: { type: 'string' }, + 'selected-check': { type: 'string', multiple: true }, 'db-name': { type: 'string' }, + 'run-index': { type: 'string' }, + 'restart-spec': { type: 'string' }, out: { type: 'string' }, 'parent-attempt-id': { type: 'string' }, + 'mutation-shard-index': { type: 'string' }, 'mutation-shard-count': { type: 'string' }, + 'resume-from': { type: 'string' }, 'checkpoint-out': { type: 'string' }, + 'baseline-bundle': { type: 'string' }, 'expected-calibration-json': { type: 'string' }, + 'max-runtime-minutes': { type: 'string' }, 'image-id': { type: 'string' }, + } }); + const a: MutationArgs = { app: values.app, url: values.url, mutations: values.mutations, + level: values.level, spec: values.spec, backend: values.backend, track: values.track, + recipe: values.recipe, selectedCheckKeys: values['selected-check'], dbName: values['db-name'], + runIndex: values['run-index'] ?? '0', + restartSpec: values['restart-spec'] === undefined ? undefined + : parseRuntimeControlSpec(JSON.parse(values['restart-spec'])), + out: values.out, parentAttemptId: values['parent-attempt-id'], + mutationShardIndex: values['mutation-shard-index'] === undefined + ? undefined : Number(values['mutation-shard-index']), + mutationShardCount: values['mutation-shard-count'] === undefined + ? undefined : Number(values['mutation-shard-count']), + resumeFrom: values['resume-from'] && resolve(values['resume-from']), + checkpointOut: values['checkpoint-out'] && resolve(values['checkpoint-out']), + baselineBundle: values['baseline-bundle'] && resolve(values['baseline-bundle']), + expectedCalibrationIdentity: values['expected-calibration-json'] === undefined + ? undefined : JSON.parse(values['expected-calibration-json']) as JsonRecord, + maxRuntimeMinutes: values['max-runtime-minutes'] === undefined + ? 60 : Number(values['max-runtime-minutes']), + imageId: values['image-id'] }; + if (!a.app || !a.url || !a.mutations || !a.level || !a.recipe) { + throw new Error( + "Usage: node dist/grader/mutation-test.js --app --url --mutations " + + "--level --recipe ", + ); + } + let url: URL; + try { url = new URL(a.url); } + catch { throw new Error('--url must be a valid HTTP or HTTPS URL'); } + if (url.protocol !== 'http:' && url.protocol !== 'https:') { + throw new Error('--url must use HTTP or HTTPS'); + } + if (!Number.isInteger(Number(a.level)) || Number(a.level) < 1) { + throw new Error('--level must be a positive integer'); + } + const shardFields = [a.mutationShardIndex, a.mutationShardCount] + .filter(value => value !== undefined); + if (shardFields.length === 1) { + throw new Error('--mutation-shard-index and --mutation-shard-count must be supplied together'); + } + if (a.mutationShardCount !== undefined + && (!Number.isInteger(a.mutationShardIndex) || !Number.isInteger(a.mutationShardCount) + || a.mutationShardIndex! < 0 || a.mutationShardCount < 1 + || a.mutationShardIndex! >= a.mutationShardCount)) { + throw new Error('--mutation-shard-index must be within the positive shard count'); + } + a.maxRuntimeMinutes ??= 60; + if (!Number.isFinite(a.maxRuntimeMinutes) || a.maxRuntimeMinutes < 1 + || a.maxRuntimeMinutes > 120) { + throw new Error('--max-runtime-minutes must be from 1 through 120'); + } + if (a.resumeFrom && !a.checkpointOut) a.checkpointOut = a.resumeFrom; + return { ...a, app: a.app, url: a.url, mutations: a.mutations, level: a.level, recipe: a.recipe, + maxRuntimeMinutes: a.maxRuntimeMinutes, + mutationAttemptId: `mutation-${new Date().toISOString().replace(/[:.]/g, "-")}` }; +} + +class MutationBatchDeadlineError extends Error {} + +export function remainingMutationBatchMs(deadlineMs: number, nowMs: number = Date.now()): number { + const remaining = Math.floor(deadlineMs - nowMs); + if (remaining <= 0) throw new MutationBatchDeadlineError('mutation batch deadline reached'); + return remaining; +} + +// Startup owns application initialization, including migrations outside module init. +export async function resetMutationDatabase(a: MutationArgs, deadlineMs: number | null, + control = controlAppServer): Promise { + const exec: TextCommandExecutor = deadlineMs === null ? execFileSync : ((file, commandArgs, options) => + execFileSync(file, commandArgs, { ...options, + timeout: Math.min(options.timeout, remainingMutationBatchMs(deadlineMs)) })); + try { + const requiresReseed = STACK_ADAPTER_REGISTRY.get(a.backend!).reset.requiresReseed; + const restartSpec = a.reseedOnReset && requiresReseed ? a.restartSpec : undefined; + if (a.reseedOnReset && requiresReseed && !restartSpec) { + throw new Error(`track ${a.track} requires a lease-authenticated --restart-spec to reseed after reset`); + } + const signal = deadlineMs === null ? null + : AbortSignal.timeout(remainingMutationBatchMs(deadlineMs)); + if (restartSpec) await control(restartSpec, "stop", { signal, exec }); + resetBackend({ backend: a.backend!, app: a.app!, exec }); + if (restartSpec) await control(restartSpec, "start", { signal, exec }); + } catch (error) { + if (deadlineMs !== null && Date.now() >= deadlineMs) { + throw new MutationBatchDeadlineError('mutation batch deadline reached', { cause: error }); + } + throw error; + } +} + +export function mutationClientCommand(backend: string, command: string, args: readonly string[], + timeout: number, exec: TextCommandExecutor = execFileSync): string { + const { lease } = leaseFromEnv(process.env, { backend, active: true }); + const container = inspectBuildContainer(lease, exec); + return exec('docker', ['exec', ...codingContainerAgentExecOptions(), + '-w', `${CODING_CONTAINER_APP_ROOT}/client`, container.id, + ...codingContainerAgentCommand(command, args)], + { encoding: 'utf8', stdio: 'pipe', timeout }); +} + +function rebuildClientAfterSourceChange(a: MutationArgs, deadlineMs: number): void { + const timeout = deadlineMs - Date.now(); + if (timeout <= 0) throw new MutationBatchDeadlineError(); + try { + mutationClientCommand(a.backend!, 'npm', ['run', 'build'], timeout); + } catch (cause) { + if (Date.now() >= deadlineMs) throw new MutationBatchDeadlineError(); + throw new Error(`client build failed after source change: ${mutationFailureMessage(cause)}`, { cause }); + } +} + +export function mutationGradeArguments(a: MutationArgs, reportPath: string): string[] { + const gradeArgs: string[] = [ + GRADER, + "--url", + a.url!, + "--level", + a.level!, + "--out", + reportPath, + "--spec", + a.spec!, + "--backend", + a.backend!, + "--track", + a.track!, + "--app", + a.app!, + ]; + if (a.dbName) gradeArgs.push("--db-name", a.dbName); + if (a.restartSpec) gradeArgs.push("--restart-spec", JSON.stringify(a.restartSpec)); + if (a.mutationAttemptId) gradeArgs.push("--parent-attempt-id", a.mutationAttemptId); + if (a.recipe) gradeArgs.push("--recipe", a.recipe); + if (a.expectedRecipeSha256) { + gradeArgs.push("--expected-recipe-sha256", a.expectedRecipeSha256); + } + for (const stableKey of a.selectedCheckKeys ?? []) { + gradeArgs.push("--selected-check", stableKey); + } + if (a.selectedCheckKeys?.length) { + gradeArgs.push("--selection-sha256", sha256(JSON.stringify([...a.selectedCheckKeys].sort()))); + } + return gradeArgs; +} + +async function grade(a: MutationArgs, reportPath: string, deadlineMs: number | null = null): Promise { + await resetMutationDatabase(a, deadlineMs); + if (existsSync(reportPath)) unlinkSync(reportPath); + const gradeArgs = mutationGradeArguments(a, reportPath); + const timeout = deadlineMs === null + ? MUTATION_GRADE_MAX_TIMEOUT_MS + : mutationGradeTimeoutMs(deadlineMs); + if (timeout === 0) throw new MutationBatchDeadlineError('mutation batch deadline reached'); + try { + execFileSync(process.execPath, gradeArgs, { + stdio: "pipe", + encoding: "utf8", + timeout, + }); + } catch (error) { + if (jsonObject(error, 'grader process error').code === 'ETIMEDOUT' && timeout < MUTATION_GRADE_MAX_TIMEOUT_MS) { + throw new MutationBatchDeadlineError('mutation grade reached the remaining batch deadline'); + } + throw error; + } + if (!existsSync(reportPath)) { + throw new Error("grader completed without producing its report"); + } + return readArtifactPayload(reportPath, { expectedKind: "grade" }); +} + +interface MutationGradeReceipt { + scenario: string; + mutationId: string | null; + status: 'running' | 'returned' | 'threw'; + report: { path: string; sha256: string | null }; +} + +// Reports stay private beside their control artifact, including failed and retried invocations. +export async function retainMutationGrade(outputPath: string, + context: Pick, + invoke: (path: string) => Promise, record: (receipt: MutationGradeReceipt) => void): Promise { + const directory = `${outputPath}.grades`; + mkdirSync(directory, { recursive: true }); + const path = join(mkdtempSync(join(directory, 'invocation-')), 'grade.json'); + const receipt: MutationGradeReceipt = { ...context, status: 'running', report: { + path: relative(dirname(outputPath), path).replaceAll('\\', '/'), sha256: null, + } }; + record(receipt); + try { + const result = await invoke(path); + receipt.status = 'returned'; + return result; + } catch (error) { + receipt.status = 'threw'; + throw error; + } finally { + if (existsSync(path)) receipt.report.sha256 = sha256(readFileSync(path)); + record(receipt); + } +} + +let args: ParsedMutationArgs; +let startedAt: number; +let startedIso: string; +const artifactPath = (id: string) => + resolve(args.out ?? join(HERE, "..", "results", `${id}.json`)); +let spec!: MutationSpec; +const gradeReports: MutationGradeReceipt[] = []; +let priorMutationControl: { path: string; sha256: string } | null = null; +let baselineBundleEvidence: { path: string; sha256: string } | null = null; +let currentControlArtifact: (() => Record) | null = null; + +function sha256(value: string | Buffer): string { + return createHash('sha256').update(value).digest('hex'); +} + +function scenarioKey(path: string): string { + return relative(resolve(HERE, '..'), path).replaceAll('\\', '/'); +} + +function checkpointGroup(path: string, mutations: MutationDefinition[], selectedCheckKeys: readonly string[]): + MutationCheckpointIdentity['groups'][number] { + const scenario = scenarioKey(path); + const scenarioSha256 = sha256(readFileSync(path)); + const mutationSha256 = sha256(JSON.stringify(mutations)); + const selectionSha256 = sha256(JSON.stringify([...selectedCheckKeys].sort())); + return { scenario, scenarioSha256, mutationSha256, selectionSha256, + identitySha256: sha256(JSON.stringify({ scenarioSha256, mutationSha256, selectionSha256 })), + mutationIds: mutations.map(mutation => mutation.id as string) }; +} + +function checkpointIdentity(groups: MutationCheckpointIdentity['groups'], shard: { index: number; count: number; + mutationIds: string[] }, track: ReturnType): MutationCheckpointIdentity { + return { + schemaVersion: 1, + engineSha256: currentEngineIdentity().sha256, + recipeSha256: args.expectedRecipeSha256, + fixtureSha256: spec.fixtureSha256, + calibrationSha256: args.expectedCalibrationIdentity?.sha256 ?? null, + imageId: args.imageId ?? null, + backend: args.backend, + track: args.track, + level: Number(args.level), + trackSha256: sha256(readFileSync(join(track.dir, TRACK_MANIFEST_FILE))), + shard: { index: shard.index, count: shard.count, mutationIds: shard.mutationIds }, + groups, + }; +} + +function resumableEvidence(path: string | undefined, identity: MutationCheckpointIdentity): + { results: MutationCheckpointResult[]; baselines: MutationCheckpointBaseline[] } { + if (!path || !existsSync(path)) return { results: [], baselines: [] }; + const prior = readArtifactPayload(path, { expectedKind: 'mutation_control' }); + const { results, baselines } = reusableMutationEvidence(prior, identity); + const shard = identity.shard as { mutationIds: string[] }; + console.log(`Resuming ${results.length}/${shard.mutationIds.length} completed mutations from ${path}`); + return { results, baselines }; +} + +export function mutationHarnessFailureArtifact(current: Record, reason: string, + completedAt: string): Record { + return { ...current, completedAt, ok: false, + outcome: { kind: 'harness_failure', phase: 'mutation-control', reason } }; +} + +function recordHarnessFailure(error: unknown): void { + const generatedAt = new Date().toISOString(); + const id = args.mutationAttemptId; + const artifact = { + id, + kind: "mutation_control", + startedAt: startedIso, + completedAt: generatedAt, + parentAttemptId: args.parentAttemptId ?? null, + identities: emptyArtifactIdentities({ + fixture: spec?.fixtureSha256 ? { id: "source-under-mutation", sha256: spec.fixtureSha256 } : null, + stackAdapter: (args.backend ?? spec?.backend) ? { id: args.backend ?? spec.backend } : null, + }), + durationMs: Date.now() - startedAt, + app: resolve(args.app), + mutations: resolve(args.mutations), + fixtureSha256: spec?.fixtureSha256 ?? null, + spec: args.spec ? resolve(args.spec) : null, + backend: args.backend ?? spec?.backend ?? null, + track: args.track ?? spec?.track ?? null, + ok: false, + gradeReports, + priorMutationControl, + baseline: { sourceBundle: baselineBundleEvidence }, + outcome: { + kind: "harness_failure", + phase: "mutation-control", + reason: mutationFailureMessage(error), + }, + }; + try { + const outputPath = artifactPath(id); + writeRunJson(outputPath, mutationHarnessFailureArtifact( + currentControlArtifact?.() ?? artifact, mutationFailureMessage(error), generatedAt)); + console.error( + `mutation harness failure: ${mutationFailureMessage(error)}\nartifact: ${outputPath}`, + ); + } catch (artifactError) { + console.error( + `mutation harness failure: ${mutationFailureMessage(error)}\nfailed to write failure artifact: ${errorMessage(artifactError)}`, + ); + } + process.exitCode = 2; +} + +async function main(): Promise { + spec = readMutationManifest(args.mutations!); + const fullMutations = spec.mutations; + const shard = args.mutationShardCount === undefined + ? { index: 0, count: 1, mutationIds: fullMutations.map(mutation => mutation.id as string), + mutations: fullMutations } + : mutationShard(fullMutations, + { index: args.mutationShardIndex!, count: args.mutationShardCount, + defaultScenario: spec.scenario }); + if (shard.mutations.length === 0) throw new Error('mutation shard has no assigned mutations'); + spec.mutations = shard.mutations; + if (args.backend && args.backend !== spec.backend) { + throw new Error( + `--backend conflicts with manifest backend ${spec.backend}`, + ); + } + if (args.track && args.track !== spec.track) { + throw new Error(`--track conflicts with manifest track ${spec.track}`); + } + args.backend = spec.backend; + args.track = spec.track; + const track = loadTrack(args.track); + const binding = resolveRecipeRelease(track, Number(args.level), args.recipe); + if (!binding) throw new Error(`${args.track} L${args.level} has no recipe release`); + args.recipe = binding.release.id; + args.expectedRecipeSha256 = binding.release.contentSha256; + const recipeRelease = binding.release; + args.dbName ??= dbName(track, Number(args.runIndex)); + args.reseedOnReset = track.reseedOnReset; + const definitions = validateMutationDefinitions(spec.mutations, + { defaultScenario: spec.scenario, requireScenario: true }); + if (!definitions.ok) { + throw new Error( + `invalid mutation manifest: ${ + definitions.issues.map((issue) => + `${issue.mutation ?? ""}:${issue.kind}` + ).join(", ") + }`, + ); + } + const groups = new Map(); + for (const [scenario, mutations] of groupMutationsByScenario(spec)) { + const declaredSpec = resolveMutationScenarioPath(scenario); + groups.set(declaredSpec, mutations); + } + if (args.spec) { + const requested = resolve(args.spec); + if (groups.size !== 1 || !groups.has(requested)) { + throw new Error('--spec conflicts with the mutation manifest scenario selection'); + } + } + // Hosted apps serve this build; development servers compile client source on demand. + const clientDist = `${CODING_CONTAINER_APP_ROOT}/client/dist`; + const cleanClientDist = spec.mutations.some(mutation => + mutationFileEdits(mutation).some(edit => edit.file.replaceAll('\\', '/').startsWith('client/'))) + && existsSync(join(args.app, 'client', 'dist')) ? `/tmp/stack-bench-mutation-${randomUUID()}-client-dist` : null; + if (cleanClientDist) mutationClientCommand(args.backend!, 'cp', + ['-R', '--', clientDist, cleanClientDist], 120_000); + + // Reject backups left by an interrupted run before grading the baseline. + for (const m of spec.mutations) { + for (const file of new Set(mutationFileEdits(m).map(edit => edit.file))) { + const stale = resolveMutationFile(args.app, file) + ".mutation-backup"; + if (existsSync(stale)) { + throw new Error( + `${stale} exists; restore the interrupted mutation backup before running again`, + ); + } + } + } + + // Catch dirty source even when no backup file remains. + assertAppSourceIdentity(args.app, spec.fixtureSha256, 'mutation fixture'); + + // Reject missing or ambiguous edit anchors before baseline grading. + for (const m of spec.mutations) { + for (const edit of mutationFileEdits(m)) { + const source = readFileSync(resolveMutationFile(args.app, edit.file), "utf8"); + const matches = source.split(edit.find).length - 1; + if (matches !== 1) { + throw new Error( + `${m.id} anchor matched ${matches} times in ${edit.file}; expected exactly once`, + ); + } + } + } + + const plans = [...groups].map(([scenarioPath, mutations]) => { + const selectedCheckKeys = releaseScenarioCheckKeys(recipeRelease, track.dir, scenarioPath, + args.selectedCheckKeys ?? null); + return { scenarioPath, scenario: scenarioKey(scenarioPath), mutations, selectedCheckKeys, + checkpoint: checkpointGroup(scenarioPath, mutations, selectedCheckKeys) }; + }); + const cleanBaselineBundle = args.baselineBundle + ? readArtifactPayload(args.baselineBundle, { expectedKind: 'grade_bundle' }) + : null; + if (cleanBaselineBundle && !args.expectedCalibrationIdentity) { + throw new Error('a reusable clean baseline requires its expected calibration identity'); + } + const checkpoint = checkpointIdentity(plans.map(plan => plan.checkpoint), shard, track); + const resumed = resumableEvidence(args.resumeFrom, checkpoint); + const results: MutationResult[] = [...resumed.results] as MutationResult[]; + const baselines: BaselineEntry[] = [...resumed.baselines] as BaselineEntry[]; + const completedIds = new Set(results.map(result => result.id)); + if (completedIds.size !== results.length) { + throw new Error('mutation checkpoint contains duplicate results'); + } + const outputPath = artifactPath(args.mutationAttemptId); + if (args.baselineBundle) baselineBundleEvidence = { + path: relative(dirname(outputPath), resolve(args.baselineBundle)).replaceAll('\\', '/'), + sha256: sha256(readFileSync(args.baselineBundle)), + }; + if (args.resumeFrom) { + let priorPath = resolve(args.resumeFrom); + if (priorPath === outputPath || (args.checkpointOut && priorPath === resolve(args.checkpointOut))) { + const retainedPath = `${priorPath}.prior-${randomUUID()}.json`; + copyFileSync(priorPath, retainedPath); + priorPath = retainedPath; + } + priorMutationControl = { path: relative(dirname(outputPath), priorPath).replaceAll('\\', '/'), + sha256: sha256(readFileSync(priorPath)) }; + } + const deadline = startedAt + args.maxRuntimeMinutes * 60_000; + + const createControlArtifact = (status: 'running' | 'incomplete' | 'complete', reason: string | null = null) => { + const ordered = [...results].sort((left, right) => + shard.mutationIds.indexOf(left.id) - shard.mutationIds.indexOf(right.id)); + const clean = ordered.filter(result => result.status === 'CAUGHT'); + const orderedBaselines = plans.map(plan => baselines.find(entry => + entry.scenario === plan.scenario)).filter((entry): entry is BaselineEntry => Boolean(entry)); + const remaining = shard.mutationIds.filter(id => !completedIds.has(id)); + return { + id: args.mutationAttemptId, + kind: 'mutation_control', + startedAt: startedIso, + completedAt: status === 'running' ? null : new Date().toISOString(), + parentAttemptId: args.parentAttemptId ?? null, + identities: emptyArtifactIdentities({ + fixture: { id: 'source-under-mutation', sha256: spec.fixtureSha256 }, + recipe: { id: recipeRelease.id, sha256: recipeRelease.contentSha256 }, + stackAdapter: { id: args.backend }, + }), + durationMs: Date.now() - startedAt, + app: resolve(args.app), + mutations: resolve(args.mutations), + fixtureSha256: spec.fixtureSha256, + spec: plans.map(plan => plan.scenario), + backend: args.backend, + track: args.track, + shard: { index: shard.index, count: shard.count, mutationIds: shard.mutationIds }, + baseline: { + sourceBundle: baselineBundleEvidence, + total: orderedBaselines.reduce((sum, entry) => sum + Number(entry.total), 0), + max: orderedBaselines.reduce((sum, entry) => sum + Number(entry.max), 0), + scenarios: orderedBaselines, + }, + ok: status === 'complete' && clean.length === ordered.length + && ordered.length === shard.mutationIds.length, + ...(status === 'complete' ? {} : { outcome: { kind: 'incomplete', + phase: 'mutation-control', reason: reason ?? 'mutation batch is in progress' } }), + summary: { caught: clean.length, completed: ordered.length, + total: shard.mutationIds.length, remaining: remaining.length }, + results: ordered, + gradeReports, + priorMutationControl, + checkpoint: { ...checkpoint, status, maxRuntimeMinutes: args.maxRuntimeMinutes, + updatedAt: new Date().toISOString() }, + }; + }; + currentControlArtifact = () => createControlArtifact('incomplete'); + + const persist = (status: 'running' | 'incomplete' | 'complete', reason: string | null = null) => { + assertAppSourceIdentity(args.app, spec.fixtureSha256, + 'mutation fixture before checkpoint'); + const artifact = createControlArtifact(status, reason); + writeRunJson(outputPath, artifact); + if (args.checkpointOut && resolve(args.checkpointOut) !== outputPath) { + const rebase = (ref: { path: string; sha256: string | null }) => ({ ...ref, + path: relative(dirname(resolve(args.checkpointOut!)), resolve(dirname(outputPath), ref.path)).replaceAll('\\', '/') }); + writeRunJson(args.checkpointOut, { ...artifact, + baseline: { ...artifact.baseline, sourceBundle: baselineBundleEvidence ? rebase(baselineBundleEvidence) : null }, + gradeReports: gradeReports.map(receipt => ({ ...receipt, report: rebase(receipt.report) })), + priorMutationControl: priorMutationControl ? rebase(priorMutationControl) : null }); + } + return artifact; + }; + const invokeGrade = (mutationId: string | null) => { + const index = gradeReports.length; + return retainMutationGrade(outputPath, { scenario: scenarioKey(args.spec!), mutationId }, + path => grade(args, path, deadline), receipt => { + gradeReports[index] = receipt; + // During a mutant invocation source differs by design; this is a running receipt, not acceptance. + writeRunJson(outputPath, createControlArtifact('running')); + }); + }; + const stopAtBudget = () => { + const artifact = persist('incomplete', + `mutation batch reached its ${args.maxRuntimeMinutes} minute limit`); + console.log(`\n${artifact.summary.completed}/${artifact.summary.total} mutations completed; ` + + `${artifact.summary.remaining} remain`); + console.log(`checkpoint: ${args.checkpointOut ?? outputPath}`); + process.exitCode = 3; + }; + + for (const plan of plans) { + const { scenarioPath, scenario, mutations, selectedCheckKeys } = plan; + const pending = mutations.filter((mutation: MutationDefinition) => !completedIds.has(mutation.id as string)); + if (pending.length === 0) continue; + if (Date.now() >= deadline) return stopAtBudget(); + args.spec = scenarioPath; + args.selectedCheckKeys = selectedCheckKeys; + let baseline; + if (cleanBaselineBundle) { + const reused = reusableMutationBaseline(cleanBaselineBundle, { + backend: args.backend, + track: args.track, + level: Number(args.level), + fixtureSha256: spec.fixtureSha256, + recipe: { id: recipeRelease.id, sha256: recipeRelease.contentSha256 }, + identities: { + engine: currentEngineIdentity(), + calibration: args.expectedCalibrationIdentity, + stackAdapter: { id: args.backend }, + }, + selectedCheckKeys, + }); + if (!reused.ok) { + throw new Error(`cannot reuse clean baseline for ${scenarioPath}: ${reused.reason}`); + } + baseline = reused.report; + console.log(`Baseline (verified clean evidence, ${scenarioPath})...`); + } else { + console.log(`Baseline (unmutated app, ${scenarioPath})...`); + try { + baseline = await invokeGrade(null); + } catch (error) { + if (error instanceof MutationBatchDeadlineError) return stopAtBudget(); + throw error; + } + const validation = validateMutationBaseline(baseline, mutations); + if (!validation.ok && isRetryableMutationBaseline(validation.issues)) { + console.log(' transient baseline failure; retrying once'); + try { + baseline = await invokeGrade(null); + } catch (error) { + if (error instanceof MutationBatchDeadlineError) return stopAtBudget(); + throw error; + } + } + } + const baselineValidation = validateMutationBaseline(baseline, mutations); + if (!baselineValidation.ok) { + throw new Error( + `reference baseline is not known-good for ${scenarioPath}: ${ + JSON.stringify(baselineValidation.issues) + }`, + ); + } + console.log( + ` baseline: ${baseline.total}/${baseline.max} ${ + (baseline.features ?? []).map((f) => `F${f.id}:${(f as NonNullable[number]).score}`).join(" ") + }\n`, + ); + const baselineEntry = { scenario, identitySha256: plan.checkpoint.identitySha256, + total: baseline.total, max: baseline.max }; + const priorBaseline = baselines.findIndex(entry => entry.scenario === scenario); + if (priorBaseline === -1) baselines.push(baselineEntry); + else baselines[priorBaseline] = baselineEntry; + + for (const m of pending) { + if (Date.now() >= deadline) return stopAtBudget(); + const byFile = new Map(); + for (const edit of mutationFileEdits(m)) { + const target = resolveMutationFile(args.app, edit.file); + if (!byFile.has(target)) { + byFile.set(target, { + target, + backup: `${target}.mutation-backup`, + original: readFileSync(target, "utf8"), + edits: [], + }); + } + byFile.get(target)!.edits.push(edit); + } + const files = [...byFile.values()]; + const clientChanged = files.some(file => relative(args.app!, file.target) + .split(sep)[0] === 'client'); + const backedUp: MutationFile[] = []; + let r: GradeReport | undefined; + let classified: ReturnType | undefined; + let deadlineReached = false; + let mutationError: unknown = null; + try { + for (const file of files) { + copyFileSync(file.target, file.backup); + backedUp.push(file); + } + for (const file of files) { + writeFileSync(file.target, + file.edits.reduce((src, edit) => src.replace(edit.find, edit.replace), + file.original)); + } + if (clientChanged) rebuildClientAfterSourceChange(args, deadline); + r = await invokeGrade(m.id as string); + classified = classifyMutationResult( + baseline as Parameters[0], + r as Parameters[1], + m, + ); + if (isRetryableMutationResult(classified.status)) { + console.log(` ${classified.status} result; retrying once`); + r = await invokeGrade(m.id as string); + classified = classifyMutationResult( + baseline as Parameters[0], + r as Parameters[1], + m, + ); + } + } catch (error) { + if (error instanceof MutationBatchDeadlineError) deadlineReached = true; + else mutationError = error; + } + + const cleanupErrors: Error[] = []; + for (const file of backedUp) { + try { + restoreMutationSource(file); + } catch (error) { + cleanupErrors.push(new Error(`cannot restore ${file.target}: ${errorMessage(error)}`, + { cause: error })); + } + } + for (const file of files) { + try { + if (existsSync(file.backup) || readFileSync(file.target, 'utf8') !== file.original) { + cleanupErrors.push(new Error(`restore verification failed for ${file.target}`)); + } + } catch (error) { + cleanupErrors.push(new Error(`cannot verify restored source ${file.target}: ${errorMessage(error)}`, + { cause: error })); + } + } + if (clientChanged) { + try { + mutationClientCommand(args.backend!, 'rm', ['-rf', '--', clientDist], 120_000); + if (cleanClientDist) mutationClientCommand(args.backend!, 'cp', + ['-R', '--', cleanClientDist, clientDist], 120_000); + } catch (error) { + cleanupErrors.push(new Error(`cannot restore the built client: ${errorMessage(error)}`, + { cause: error })); + } + } + // A normal error leaves enough budget to restore the clean runtime. A + // deadline stop leaves clean source and lets the lease owner stop it. + if (mutationError !== null && cleanupErrors.length === 0) { + try { + await resetMutationDatabase(args, deadline); + } catch (error) { + cleanupErrors.push(new Error(`cannot restore the clean runtime: ${errorMessage(error)}`, + { cause: error })); + } + } + if (cleanupErrors.length > 0) { + const errors = mutationError === null ? cleanupErrors : [mutationError, ...cleanupErrors]; + throw new AggregateError(errors, + 'mutation cleanup failed; do not reuse this app source'); + } + if (mutationError !== null) throw mutationError; + if (deadlineReached) return stopAtBudget(); + if (!r || !classified) throw new Error('mutation grade completed without a result'); + results.push({ id: m.id, scenario, + targets: mutationTargetKeys(m), ...classified }); + completedIds.add(m.id); + persist('running'); + console.log( + `${classified.status.padEnd(20)} ${m.id} — expected ${ + classified.targetKeys.join(", ") + }`, + ); + if (classified.regressions.length) { + console.log( + ` failed criteria: ${ + classified.regressions.map((item) => item.key).join(", ") + }`, + ); + } + } + } + + // Detect any source change outside the files restored above. + assertAppSourceIdentity(args.app, spec.fixtureSha256, 'mutation fixture after worker completion'); + // Restore the clean runtime and database before releasing the worker lease. + await resetMutationDatabase(args, null); + + if (cleanClientDist) mutationClientCommand(args.backend!, 'rm', ['-rf', '--', cleanClientDist], 120_000); + const artifact = persist('complete'); + console.log(`\n${artifact.summary.caught}/${artifact.summary.total} mutations cleanly caught`); + console.log(`artifact: ${outputPath}`); + if (!artifact.ok) process.exitCode = 1; +} + +function run(): void { + try { + args = parseMutationArgs(process.argv); + } catch (error) { + console.error(errorMessage(error)); + process.exitCode = 2; + return; + } + startedAt = Date.now(); + startedIso = new Date(startedAt).toISOString(); + main().catch(recordHarnessFailure); +} + +if (process.argv[1] && fileURLToPath(import.meta.url) === process.argv[1]) run(); diff --git a/tools/stack-bench/grader/mutations/mongodb-ecommerce.json b/tools/stack-bench/grader/mutations/mongodb-ecommerce.json new file mode 100644 index 00000000000..2993dc10067 --- /dev/null +++ b/tools/stack-bench/grader/mutations/mongodb-ecommerce.json @@ -0,0 +1,2661 @@ +{ + "schemaVersion": 3, + "fixtureSha256": "d256346679183bca23b282e5bba6f0e9225e7cca4ab20d5009fc985e60941052", + "backend": "mongodb", + "track": "ecommerce", + "note": "Mutation definitions for the MongoDB ecommerce reference.", + "mutations": [ + { + "id": "recommendation-dismissal-lost-on-restart", + "scenario": "tracks/ecommerce/scenarios/progression-recommendation-feedback.json", + "targets": [ + "ecommerce.spec.state-durability.recommendation-feedback-restart.504c" + ], + "desc": "Erase saved recommendation dismissals when the application starts again.", + "file": "server/src/index.ts", + "edits": [ + { + "find": " await mongoose.connect(DATABASE_URL);", + "replace": " await mongoose.connect(DATABASE_URL);\n await Dismissal.deleteMany({});" + } + ] + }, + { + "id": "pending-order-item-return-accepted", + "scenario": "tracks/ecommerce/scenarios/progression-order-return-boundary.json", + "targets": [ + "ecommerce.returns-pricing.cancellation-and-return.3f" + ], + "desc": "Accept a pending order return and restore its stock before shipment.", + "file": "server/src/index.ts", + "edits": [ + { + "find": "if (!['shipped', 'delivered'].includes(value.status)) throw new Error('No shipped order found');", + "replace": "if (!['pending', 'shipped', 'delivered'].includes(value.status)) throw new Error('No shipped order found');" + } + ] + }, + { + "id": "staff-admin-access-survives-role-removal", + "scenario": "tracks/ecommerce/scenarios/progression-staff-roles.json", + "targets": [ + "ecommerce.spec.access-control.staff-role-revocation.621d" + ], + "desc": "Keep administrator access after changing the assigned role back to staff.", + "file": "server/src/progression.ts", + "edits": [ + { + "find": " target.isAdmin = role === \"admin\";", + "replace": " target.isAdmin = target.isAdmin || role === \"admin\";" + } + ] + }, + { + "id": "shipping-counts-sale-twice", + "scenario": "tracks/ecommerce/scenarios/progression-shipping-accounting.json", + "targets": [ + "ecommerce.inventory-operations.shipping-accounting.202e" + ], + "desc": "Shipping succeeds but doubles the completed sale value in authoritative revenue.", + "file": "server/src/index.ts", + "edits": [ + { + "find": " order.status = \"shipped\";\n await order.save();", + "replace": " order.status = \"shipped\";\n order.total *= 2;\n await order.save();" + } + ] + }, + { + "id": "signup-does-not-expose-created-account", + "scenario": "tracks/ecommerce/scenarios/01-account-create.json", + "targets": [ + "ecommerce.feature.accounts.accounts.1a" + ], + "desc": "Signup succeeds but the client discards the created account identity from its current session view.", + "file": "client/src/App.tsx", + "edits": [ + { + "find": " saveSession(data.token, data.user);\n };\n\n const handleSignIn", + "replace": " saveSession(data.token, { ...data.user, username: \"\" });\n };\n\n const handleSignIn" + } + ] + }, + { + "id": "duplicate-signup-reports-success", + "scenario": "tracks/ecommerce/scenarios/01-account-duplicate.json", + "targets": [ + "ecommerce.feature.accounts.accounts.1b" + ], + "desc": "A duplicate username is reported as a successful empty signup response instead of a refusal.", + "file": "server/src/index.ts", + "edits": [ + { + "find": " if (existing) return res.status(409).json({ error: \"Username is already taken\" });", + "replace": " if (existing) return res.json({}); // mutant: duplicate signup is falsely accepted" + } + ] + }, + { + "id": "signin-skips-password-verification", + "scenario": "tracks/ecommerce/scenarios/01-account-password.json", + "targets": [ + "ecommerce.feature.accounts.accounts.1c" + ], + "desc": "Signin accepts an existing account without requiring its password to match.", + "file": "server/src/index.ts", + "edits": [ + { + "find": " if (!valid) return res.status(401).json({ error: \"Invalid username or password\" });", + "replace": " if (false && !valid) return res.status(401).json({ error: \"Invalid username or password\" });" + } + ] + }, + { + "id": "signout-keeps-current-account", + "scenario": "tracks/ecommerce/scenarios/01-account-signout.json", + "targets": [ + "ecommerce.feature.accounts.accounts.1d" + ], + "desc": "Signout disconnects the token state but leaves the current account and persisted credential in place.", + "file": "client/src/App.tsx", + "edits": [ + { + "find": " const handleSignOut = () => {\n clearSession();\n };", + "replace": " const handleSignOut = () => {\n setToken(null); // mutant: visible and persisted account state is not cleared\n };" + } + ] + }, + { + "id": "session-token-not-persisted", + "scenario": "tracks/ecommerce/scenarios/01-account-reload.json", + "targets": [ + "ecommerce.spec.state-durability.session-reload.1e" + ], + "desc": "The active session is kept only in React state and is unavailable after a page reload.", + "file": "client/src/App.tsx", + "edits": [ + { + "find": " localStorage.setItem(TOKEN_KEY, tok);\n setToken(tok);", + "replace": " void tok; // mutant: the session token is never persisted\n setToken(tok);" + } + ] + }, + { + "id": "purchase-counts-never-affect-ranking", + "scenario": "tracks/ecommerce/scenarios/01-core.json", + "targets": [ + "ecommerce.spec.live-state.ranking.2c" + ], + "desc": "The catalogue ranking ignores recorded purchases and therefore never promotes the bought item.", + "file": "server/src/index.ts", + "edits": [ + { + "find": " purchaseCount: purchaseMap.get(id) || 0,", + "replace": " purchaseCount: 0, // mutant: ranking ignores durable purchase counts" + } + ] + }, + { + "id": "signed-out-visitor-purchase-is-accepted", + "scenario": "tracks/ecommerce/scenarios/progression-signed-out-purchase.json", + "targets": [ + "ecommerce.spec.access-control.signed-out-purchase.3a" + ], + "desc": "The UI exposes purchase controls to visitors and the buy route assigns unauthenticated requests an unverified identity, allowing an actual stock-debiting order.", + "file": "client/src/App.tsx", + "edits": [ + { + "find": " const isCustomer = !!currentUser && !currentUser.isAdmin && !currentUser.isStaff;", + "replace": " const isCustomer = !currentUser?.isAdmin && !currentUser?.isStaff;" + }, + { + "file": "server/src/index.ts", + "find": "app.post(\"/api/items/:id/buy\", requireAuth, async (req, res) => {", + "replace": "app.post(\"/api/items/:id/buy\", async (req, _res, next) => {\n (req as any).user = await userFromToken(extractToken(req)) || { _id: new Types.ObjectId() };\n next();\n}, async (req, res) => {" + } + ] + }, + { + "id": "espresso-stock-row-ignores-live-updates", + "scenario": "tracks/ecommerce/scenarios/01-buying.json", + "targets": [ + "ecommerce.spec.live-state.purchase-stock.3b" + ], + "desc": "The live catalogue handler preserves a stale Espresso Machine stock projection while applying all other item updates.", + "file": "client/src/App.tsx", + "edits": [ + { + "find": " socket.on(\"items:update\", (data: ItemT[]) => setItems(data));", + "replace": " socket.on(\"items:update\", (data: ItemT[]) => setItems((previous) => data.map((item) => item.name === \"Espresso Machine\" ? { ...item, stock: previous.find((old) => old.id === item.id)?.stock ?? item.stock } : item)));" + } + ] + }, + { + "id": "restock-race-records-wrong-order-total", + "scenario": "tracks/ecommerce/scenarios/01-restock-race.json", + "targets": [ + "ecommerce.spec.concurrency-safety.restock-race.202a" + ], + "desc": "Purchases preserve stock and visible order counts but record the wrong booked total. Native mixed-race reconciliation must reject them.", + "file": "server/src/index.ts", + "edits": [ + { + "find": " total: item.price,\n });", + "replace": " total: 0, // mutant: purchase receipt loses the authoritative price\n });" + } + ] + }, + { + "id": "purchase-order-uses-zero-price", + "scenario": "tracks/ecommerce/scenarios/progression-purchasing.json", + "targets": [ + "ecommerce.feature.purchasing.purchase-order.3c" + ], + "desc": "A direct purchase records the item but stores a zero order total instead of the price paid.", + "file": "server/src/index.ts", + "edits": [ + { + "find": " total: item.price,\n });", + "replace": " total: 0, // mutant: purchase receipt loses the authoritative price\n });" + } + ] + }, + { + "id": "reload-hydrates-an-empty-cart", + "scenario": "tracks/ecommerce/scenarios/01-cart.json", + "targets": [ + "ecommerce.spec.state-durability.cart-reload.4b" + ], + "desc": "Cart hydration discards the persisted server response after reload.", + "file": "client/src/App.tsx", + "edits": [ + { + "find": " const refreshCart = useCallback(async (tok: string) => {\n const data = await apiFetch(\"/api/cart\", tok);\n setCart(data);\n }, []);", + "replace": " const refreshCart = useCallback(async (tok: string) => {\n await apiFetch(\"/api/cart\", tok);\n setCart({ items: [], total: 0 }); // mutant: persisted cart response is discarded\n }, []);" + } + ] + }, + { + "id": "shared-cart-live-events-ignored", + "scenario": "tracks/ecommerce/scenarios/01-cart.json", + "targets": [ + "ecommerce.spec.live-state.shared-cart.4c" + ], + "desc": "An already-open second session ignores committed cart update events.", + "file": "client/src/App.tsx", + "edits": [ + { + "find": " socket.on(\"cart:update\", (data: CartT) => setCart(data));", + "replace": " socket.on(\"cart:update\", (data: CartT) => setCart(current => current.items.length === 0 ? current : data)); // mutant: an empty second-session cart ignores its first remote update" + } + ] + }, + { + "id": "review-comment-is-not-persisted", + "scenario": "tracks/ecommerce/scenarios/01-review-visibility.json", + "targets": [ + "ecommerce.feature.reviews.reviews.6a" + ], + "desc": "Review submission persists an empty comment rather than the customer's submitted text.", + "file": "server/src/index.ts", + "edits": [ + { + "find": " { itemId, userId: user._id, username: user.username, rating: ratingNum,\n comment: typeof comment === \"string\" ? comment : \"\" },", + "replace": " { itemId, userId: user._id, username: user.username, rating: ratingNum,\n comment: \"\" }," + } + ] + }, + { + "id": "repeat-review-uses-a-new-owner-key", + "scenario": "tracks/ecommerce/scenarios/01-review-uniqueness.json", + "targets": [ + "ecommerce.spec.transactional-integrity.unique-review.6b" + ], + "desc": "Each review submission is stored under a fresh owner key, bypassing the one-review-per-customer constraint.", + "file": "server/src/index.ts", + "edits": [ + { + "find": " { itemId, userId: user._id },\n { itemId, userId: user._id, username: user.username, rating: ratingNum,\n comment: typeof comment === \"string\" ? comment : \"\" },", + "replace": " { itemId, userId: new Types.ObjectId() },\n { itemId, userId: new Types.ObjectId(), username: user.username, rating: ratingNum,\n comment: typeof comment === \"string\" ? comment : \"\" }," + } + ] + }, + { + "id": "live-review-average-uses-an-extra-divisor", + "scenario": "tracks/ecommerce/scenarios/01-review-rating-live.json", + "targets": [ + "ecommerce.spec.live-state.rating.6c" + ], + "desc": "The live review event divides the rating sum by one more review than actually exists.", + "file": "server/src/index.ts", + "edits": [ + { + "find": "async function broadcastReviews(itemId: string) {\n const reviews = await Review.find({ itemId }).sort({ createdAt: -1 });\n const average = reviews.length ? reviews.reduce((s, r) => s + r.rating, 0) / reviews.length : 0;", + "replace": "async function broadcastReviews(itemId: string) {\n const reviews = await Review.find({ itemId }).sort({ createdAt: -1 });\n const average = reviews.length ? reviews.reduce((s, r) => s + r.rating, 0) / (reviews.length + 1) : 0;" + } + ] + }, + { + "id": "warehouse-view-omits-one-location", + "scenario": "tracks/ecommerce/scenarios/01-warehouse-admin-staff.json", + "targets": [ + "ecommerce.feature.warehouse-admin.warehouse-view.7b" + ], + "desc": "The admin warehouse projection truncates the final item-location row.", + "file": "client/src/App.tsx", + "edits": [ + { + "find": " {overview.locations.map((loc) => (", + "replace": " {overview.locations.slice(0, -1).map((loc) => (" + } + ] + }, + { + "id": "unauthenticated-purchase-defaults-to-admin", + "scenario": "tracks/ecommerce/scenarios/01-purchase-session.json", + "targets": [ + "ecommerce.spec.access-control.purchase-session.101a" + ], + "desc": "The purchase endpoint drops authentication and assigns sessionless purchases to the seeded administrator.", + "file": "server/src/index.ts", + "edits": [ + { + "find": "app.post(\"/api/items/:id/buy\", requireAuth, async (req, res) => {", + "replace": "app.post(\"/api/items/:id/buy\", async (req, res) => {" + }, + { + "find": " const user = (req as any).user;\n const order = await Order.create({", + "replace": " const user = (req as any).user || await User.findOne({ username: \"admin\" });\n const order = await Order.create({" + } + ] + }, + { + "id": "direct-purchase-total-ignores-store-price", + "scenario": "tracks/ecommerce/scenarios/01-server-price.json", + "targets": [ + "ecommerce.spec.transactional-integrity.server-price.104a" + ], + "desc": "The direct purchase creates one order but records a zero total rather than the store's current price.", + "file": "server/src/index.ts", + "edits": [ + { + "find": " total: item.price,\n });", + "replace": " total: 0, // mutant: direct purchase ignores the authoritative price\n });" + } + ] + }, + { + "id": "cart-hydration-loses-account-state", + "scenario": "tracks/ecommerce/scenarios/progression-account-state-reload.json", + "targets": [ + "ecommerce.spec.state-durability.account-state-recovery.105a" + ], + "desc": "Reload hydration discards the account's persisted cart response.", + "file": "client/src/App.tsx", + "edits": [ + { + "find": " const refreshCart = useCallback(async (tok: string) => {\n const data = await apiFetch(\"/api/cart\", tok);\n setCart(data);\n }, []);", + "replace": " const refreshCart = useCallback(async (tok: string) => {\n await apiFetch(\"/api/cart\", tok);\n setCart({ items: [], total: 0 }); // mutant: account state is discarded on hydration\n }, []);" + } + ] + }, + { + "id": "reconnect-hydration-loses-account-state", + "scenario": "tracks/ecommerce/scenarios/progression-account-state-reconnect.json", + "targets": [ + "ecommerce.spec.state-durability.account-state-recovery.105b" + ], + "desc": "The initial account cart loads correctly, but after network restoration the client ignores both refreshed and pushed cart state.", + "file": "client/src/App.tsx", + "edits": [ + { + "find": " useEffect(() => {\n const socket = io({ auth: token ? { token } : {} });", + "replace": " useEffect(() => {\n const clearAccountOffline = () => {\n setCurrentUser(null);\n setCart({ items: [], total: 0 });\n };\n window.addEventListener(\"offline\", clearAccountOffline, { once: true });\n const socket = io({ auth: token ? { token } : {} });" + } + ] + }, + { + "id": "order-history-is-not-owner-scoped", + "scenario": "tracks/ecommerce/scenarios/01-order-ownership.json", + "targets": [ + "ecommerce.spec.access-control.order-ownership.106a" + ], + "desc": "Order history returns every customer's orders instead of filtering by the authenticated owner.", + "file": "server/src/index.ts", + "edits": [ + { + "find": " const orders = await Order.find({ userId }).sort({ createdAt: -1 });", + "replace": " const orders = await Order.find({}).sort({ createdAt: -1 });" + } + ] + }, + { + "id": "revenue-aggregation-ignores-order-totals", + "scenario": "tracks/ecommerce/scenarios/progression-books-balance.json", + "targets": [ + "ecommerce.spec.transactional-integrity.books-balance.107a" + ], + "desc": "The admin revenue aggregation counts every order as zero regardless of its stored total.", + "file": "server/src/index.ts", + "edits": [ + { + "find": " { $group: { _id: null, total: { $sum: { $subtract: [\"$total\", { $ifNull: [\"$refundTotal\", 0] }] } } } },", + "replace": " { $group: { _id: null, total: { $sum: 0 } } }," + } + ] + }, + { + "id": "unpurchased-review-is-accepted", + "scenario": "tracks/ecommerce/scenarios/01-review-eligibility.json", + "targets": [ + "ecommerce.spec.access-control.review-eligibility.108a" + ], + "desc": "The review endpoint bypasses its completed-purchase eligibility check.", + "file": "server/src/index.ts", + "edits": [ + { + "find": " if (!hasPurchased) {\n return res.status(403).json({ error: \"You can only review items you have purchased\" });\n }", + "replace": " if (false && !hasPurchased) {\n return res.status(403).json({ error: \"You can only review items you have purchased\" });\n }" + } + ] + }, + { + "id": "purchased-review-ui-does-not-submit", + "scenario": "tracks/ecommerce/scenarios/01-review-eligibility.json", + "targets": [ + "ecommerce.spec.access-control.review-eligibility.108b" + ], + "desc": "The review form discards valid customer submissions. Direct authorized and unauthorized review calls retain their normal behavior.", + "file": "client/src/App.tsx", + "edits": [ + { + "find": " const handleReviewSubmit = async (itemId: string, rating: number, comment: string) => {\n setReviewError(\"\");", + "replace": " const handleReviewSubmit = async (itemId: string, rating: number, comment: string) => {\n setReviewError(\"Review submission unavailable\");\n return;" + } + ] + }, + { + "id": "external-stock-polling-disabled", + "scenario": "tracks/ecommerce/scenarios/01-external-live-sync.json", + "targets": [ + "ecommerce.spec.external-data-sync.external-stock.901a" + ], + "desc": "The server stops reconciling direct database stock writes into live catalogue events.", + "file": "server/src/index.ts", + "edits": [ + { + "find": " broadcastItems().catch((err) => console.error(\"broadcastItems poll failed\", err));", + "replace": " // mutant: direct database stock changes are never reconciled" + } + ] + }, + { + "id": "server-restart-disables-catalog-recovery", + "scenario": "tracks/ecommerce/scenarios/01-external-server-restart-sync.json", + "targets": [ + "ecommerce.spec.external-data-sync.external-stock.901c" + ], + "desc": "After a socket disconnect, the existing page ignores both reconnect refreshes and later catalogue snapshots.", + "file": "client/src/App.tsx", + "edits": [ + { + "find": " const socketRef = useRef(null);\n\n const saveSession", + "replace": " const socketRef = useRef(null);\n const acceptCatalogRecovery = useRef(true);\n\n const saveSession" + }, + { + "find": " socket.on(\"connect\", () => {\n refreshItems().catch((err) => console.error(err));", + "replace": " socket.on(\"disconnect\", () => { acceptCatalogRecovery.current = false; });\n socket.on(\"connect\", () => {\n if (acceptCatalogRecovery.current) refreshItems().catch((err) => console.error(err));" + }, + { + "find": " socket.on(\"items:update\", (data: ItemT[]) => setItems(data));", + "replace": " socket.on(\"items:update\", (data: ItemT[]) => { if (acceptCatalogRecovery.current) setItems(data); });" + } + ] + }, + { + "id": "reconnect-generation-ignores-current-catalog", + "scenario": "tracks/ecommerce/scenarios/01-external-reconnect-sync.json", + "targets": [ + "ecommerce.spec.external-data-sync.external-stock.901d" + ], + "desc": "After the browser goes offline, the existing page ignores reconnect refreshes and subsequent catalogue events.", + "file": "client/src/App.tsx", + "edits": [ + { + "find": " const socketRef = useRef(null);\n\n const saveSession", + "replace": " const socketRef = useRef(null);\n const acceptCatalogUpdates = useRef(true);\n useEffect(() => {\n const stopCatalogRecovery = () => { acceptCatalogUpdates.current = false; };\n window.addEventListener(\"offline\", stopCatalogRecovery);\n return () => window.removeEventListener(\"offline\", stopCatalogRecovery);\n }, []);\n\n const saveSession" + }, + { + "find": " setItems(data.items);", + "replace": " if (acceptCatalogUpdates.current) setItems(data.items);" + }, + { + "find": " socket.on(\"items:update\", (data: ItemT[]) => setItems(data));", + "replace": " socket.on(\"items:update\", (data: ItemT[]) => {\n if (acceptCatalogUpdates.current) setItems(data);\n });" + } + ] + }, + { + "id": "open-review-list-ignores-live-update", + "scenario": "tracks/ecommerce/scenarios/progression-open-list-live.json", + "targets": [ + "ecommerce.spec.live-state.open-list.902a" + ], + "desc": "The already-open review list ignores a committed review update from another client.", + "file": "client/src/App.tsx", + "edits": [ + { + "find": " setItemDetail((prev) => (prev && prev.id === payload.itemId ? { ...prev, reviews: payload.reviews, average: payload.average } : prev));", + "replace": " void payload; // mutant: the already-open review list ignores committed updates" + } + ] + }, + { + "id": "cancel-does-not-restore-stock-feature", + "scenario": "tracks/ecommerce/scenarios/02-order-cancellation-core.json", + "targets": [ + "ecommerce.returns-pricing.cancellation-and-return.3a" + ], + "desc": "Cancellation changes order state but skips restoration of its recorded warehouse allocations.", + "file": "server/src/index.ts", + "edits": [ + { + "find": " {item_id:line.itemId,warehouse_id:allocation.warehouseId}, {$inc:{quantity:allocation.quantity}}, {session});", + "replace": " {item_id:line.itemId,warehouse_id:allocation.warehouseId}, {$inc:{quantity:0}}, {session});" + } + ] + }, + { + "id": "cancellation-accounting-loses-stock-restoration", + "scenario": "tracks/ecommerce/scenarios/02-invariants.json", + "targets": [ + "ecommerce.returns-pricing.refund-accounting.203a" + ], + "desc": "Cancellation removes revenue and changes order status, but loses the original warehouse stock restoration. The native refund-accounting assertion must detect this.", + "file": "server/src/index.ts", + "edits": [ + { + "find": " {item_id:line.itemId,warehouse_id:allocation.warehouseId}, {$inc:{quantity:allocation.quantity}}, {session});", + "replace": " {item_id:line.itemId,warehouse_id:allocation.warehouseId}, {$inc:{quantity:0}}, {session});" + } + ] + }, + { + "id": "cancel-does-not-restore-stock-fresh-client", + "scenario": "tracks/ecommerce/scenarios/02-self-contained.json", + "targets": [ + "ecommerce.inventory-operations.stock-conservation.202b", + "ecommerce.inventory-operations.stock-conservation.202c" + ], + "desc": "Cancellation changes order state but skips restoration, so a fresh client reads the persisted shortfall.", + "file": "server/src/index.ts", + "edits": [ + { + "find": " {item_id:line.itemId,warehouse_id:allocation.warehouseId}, {$inc:{quantity:allocation.quantity}}, {session});", + "replace": " {item_id:line.itemId,warehouse_id:allocation.warehouseId}, {$inc:{quantity:0}}, {session});" + } + ] + }, + { + "id": "cancel-restores-stock-but-keeps-pending-status", + "scenario": "tracks/ecommerce/scenarios/02-order-cancellation-history.json", + "targets": [ + "ecommerce.returns-pricing.cancellation-and-return.3b" + ], + "desc": "Cancellation restores allocations but writes pending back to order history.", + "file": "server/src/index.ts", + "edits": [ + { + "find": " value.status = \"cancelled\";\n await value.save({session});", + "replace": " value.status = \"pending\";\n await value.save({session});" + } + ] + }, + { + "id": "cancelled-order-remains-in-revenue-feature", + "scenario": "tracks/ecommerce/scenarios/02-order-cancellation-core.json", + "targets": [ + "ecommerce.returns-pricing.cancellation-and-return.3a" + ], + "desc": "Admin revenue includes cancelled orders even though cancellation otherwise succeeds.", + "file": "server/src/index.ts", + "edits": [ + { + "find": "async function getRevenue(): Promise {\n const rows = await Order.aggregate([\n { $match: { status: { $ne: \"cancelled\" } } },", + "replace": "async function getRevenue(): Promise {\n const rows = await Order.aggregate([\n { $match: {} }," + } + ] + }, + { + "id": "cancelled-order-remains-in-revenue-invariant", + "scenario": "tracks/ecommerce/scenarios/02-invariants.json", + "targets": [ + "ecommerce.returns-pricing.refund-accounting.203a" + ], + "desc": "Admin revenue includes cancelled orders even though cancellation otherwise succeeds.", + "file": "server/src/index.ts", + "edits": [ + { + "find": "async function getRevenue(): Promise {\n const rows = await Order.aggregate([\n { $match: { status: { $ne: \"cancelled\" } } },", + "replace": "async function getRevenue(): Promise {\n const rows = await Order.aggregate([\n { $match: {} }," + } + ] + }, + { + "id": "operator-authorization-allows-customer-transfer", + "scenario": "tracks/ecommerce/scenarios/02-strengthened.json", + "targets": [ + "ecommerce.operations-access.operator-authorization.201a" + ], + "desc": "The transfer route keeps authentication but drops its administrator role gate.", + "file": "server/src/index.ts", + "edits": [ + { + "find": "app.post(\"/api/admin/transfer\", requireAuth, requireAdmin, async (req, res) => {", + "replace": "app.post(\"/api/admin/transfer\", requireAuth, async (req, res) => {" + } + ] + }, + { + "id": "customer-can-ship-order-direct-1-1", + "scenario": "tracks/ecommerce/scenarios/02-server-actions.json", + "targets": [ + "ecommerce.operations-access.operator-authorization.201c" + ], + "desc": "The shipping route keeps authentication but drops its staff role gate.", + "file": "server/src/index.ts", + "edits": [ + { + "find": "app.post(\"/api/fulfilment/ship\", requireAuth, requireStaff, async (req, res) => {", + "replace": "app.post(\"/api/fulfilment/ship\", requireAuth, async (req, res) => {" + } + ] + }, + { + "id": "customer-can-cancel-foreign-order-1-1", + "scenario": "tracks/ecommerce/scenarios/02-server-actions.json", + "targets": [ + "ecommerce.operations-access.order-owner.204a" + ], + "desc": "Cancellation retains authentication and pending-state validation but drops order ownership.", + "file": "server/src/index.ts", + "edits": [ + { + "find": " const value = orderId ? await Order.findOne({ _id: orderId, userId: user._id }).session(session) : null;\n if (!value) return null;\n if (value.status !== \"pending\") throw new Error(\"Order cannot be cancelled\");", + "replace": " const value = orderId ? await Order.findOne({ _id: orderId }).session(session) : null;\n if (!value) return null;\n if (value.status !== \"pending\") throw new Error(\"Order cannot be cancelled\");" + } + ] + }, + { + "id": "queue-depth-lags-one-order", + "scenario": "tracks/ecommerce/scenarios/02-fulfilment-live.json", + "targets": [ + "ecommerce.operations-access.fulfilment-queue.1a" + ], + "desc": "The queue renders every order but its visible depth remains one behind.", + "file": "client/src/App.tsx", + "edits": [ + { + "find": "Orders waiting: {queue.depth}", + "replace": "Orders waiting: {Math.max(0, queue.depth - 1)}" + } + ] + }, + { + "id": "ship-acknowledges-without-changing-status", + "scenario": "tracks/ecommerce/scenarios/02-fulfilment-ship.json", + "targets": [ + "ecommerce.operations-access.fulfilment-queue.1c" + ], + "desc": "Shipping returns success but writes pending back to the order, leaving both live views unchanged.", + "file": "server/src/index.ts", + "edits": [ + { + "find": " order.status = \"shipped\";\n await order.save();", + "replace": " order.status = \"pending\";\n await order.save();" + } + ] + }, + { + "id": "customer-sees-fulfilment-navigation", + "scenario": "tracks/ecommerce/scenarios/02-features.json", + "targets": [ + "ecommerce.operations-access.fulfilment-queue.1d" + ], + "desc": "Expose the protected staff area to signed-in customers, including its navigation and content.", + "file": "client/src/App.tsx", + "edits": [ + { + "find": " {(currentUser?.isStaff || currentUser?.isAdmin) && (\n ", + "replace": " setState((value: any) => ({ ...value, preference: { ...preference, order: !preference.order } }))} />" + }, + { + "find": "function SupportTicket({ ticket, user, orders, act }: any) {", + "replace": "function OrderNotificationToggle({ on, onToggle }: { on: boolean; onToggle: () => void }) {\n const [shown] = useState(on); // mutant: the toggle keeps the state loaded when the card opened\n return ;\n}\n\nfunction SupportTicket({ ticket, user, orders, act }: any) {" + } + ] + }, + { + "id": "role-editor-snaps-back-to-stored-role", + "scenario": "tracks/ecommerce/scenarios/progression-staff-roles.json", + "targets": [ + "ecommerce.progression.staff-roles.staff-roles.621c" + ], + "desc": "Pressing Save persists the role but resets the dropdown to the role that was stored before the save, so the assignment is not visible until a reload.", + "file": "client/src/ProgressionPanel.tsx", + "edits": [ + { + "find": " ", + "replace": " " + } + ] + }, + { + "id": "queue-ignores-live-fulfilment-updates", + "scenario": "tracks/ecommerce/scenarios/02-fulfilment-live.json", + "targets": [ + "ecommerce.spec.live-state.fulfilment-queue.1a" + ], + "desc": "The open staff queue ignores live fulfilment events, so a new order appears only after a reload.", + "file": "client/src/App.tsx", + "edits": [ + { + "find": " socket.on(\"fulfilment:update\", (data: FulfilmentQueueT) => setFulfilmentQueue(data));", + "replace": " socket.on(\"fulfilment:update\", (data: FulfilmentQueueT) => { void data; }); // mutant: the open staff queue ignores live fulfilment updates" + } + ] + }, + { + "id": "low-stock-boundary-excludes-ten-live", + "scenario": "tracks/ecommerce/scenarios/02-low-stock.json", + "targets": [ + "ecommerce.spec.live-state.inventory-dashboard.5a" + ], + "desc": "The low-stock view uses a strict boundary, so an item that falls to exactly ten units never joins the list.", + "file": "server/src/index.ts", + "edits": [ + { + "find": " .filter((it) => it.stock <= 10)", + "replace": " .filter((it) => it.stock < 10)" + } + ] + }, + { + "id": "live-admin-updates-keep-stale-category-totals", + "scenario": "tracks/ecommerce/scenarios/02-operational-category-totals.json", + "targets": [ + "ecommerce.spec.live-state.sales-dashboard.5b" + ], + "desc": "Live admin updates keep the category totals loaded at page load, so a purchase does not move units or revenue until a reload.", + "file": "client/src/App.tsx", + "edits": [ + { + "find": " socket.on(\"admin:update\", (data: AdminOverviewT) => setAdminOverview(data));", + "replace": " socket.on(\"admin:update\", (data: AdminOverviewT) => setAdminOverview((previous) => previous ? { ...data, categories: previous.categories } : data)); // mutant: live admin updates keep the category totals loaded at page load" + } + ] + }, + { + "id": "overdraw-transfer-is-accepted", + "scenario": "tracks/ecommerce/scenarios/02-transfer-overdraw.json", + "targets": [ + "ecommerce.spec.transactional-integrity.stock-transfer-overdraw.2c" + ], + "desc": "The atomic source debit no longer requires sufficient quantity, so an overdrawn transfer succeeds and moves both warehouse totals.", + "file": "server/src/index.ts", + "edits": [ + { + "find": "{ item_id: itemId, warehouse_id: fromWarehouseId, quantity: { $gte: qty } }", + "replace": "{ item_id: itemId, warehouse_id: fromWarehouseId }" + } + ] + }, + { + "id": "transfer-totals-omit-destination-credit-live", + "scenario": "tracks/ecommerce/scenarios/02-transfer-totals.json", + "targets": [ + "ecommerce.spec.live-state.stock-transfers.2b" + ], + "desc": "A transfer debits the source but adds zero to the destination, so the two live warehouse totals do not move in opposite directions.", + "file": "server/src/index.ts", + "edits": [ + { + "find": " await Stock.findOneAndUpdate(\n { item_id: itemId, warehouse_id: toWarehouseId },\n { $inc: { quantity: qty } },\n { upsert: true }\n );", + "replace": " await Stock.findOneAndUpdate(\n { item_id: itemId, warehouse_id: toWarehouseId },\n { $inc: { quantity: 0 } },\n { upsert: true }\n );" + } + ] + }, + { + "id": "credit-checkout-ignores-wallet", + "desc": "A credit checkout pays entirely externally despite available credit.", + "scenario": "tracks/ecommerce/scenarios/progression-store-credit.json", + "targets": [ + "ecommerce.feature.store-credit.store-credit-750.750a" + ], + "file": "server/src/credit.ts", + "edits": [ + { + "find": " const creditMinor = useCredit ? Math.min(user.creditMinor, totalMinor) : 0;", + "replace": " const creditMinor = 0;" + } + ] + }, + { + "id": "credit-grant-replay-increments-balance", + "desc": "Replaying a grant applies its credit to the wallet again.", + "scenario": "tracks/ecommerce/scenarios/progression-store-credit.json", + "targets": [ + "ecommerce.spec.store-credit.production-752.752a" + ], + "file": "server/src/credit.ts", + "edits": [ + { + "find": " if (existing.amountMinor !== amountMinor) throw new Error('Reference already identifies another grant');\n return;", + "replace": " if (existing.amountMinor !== amountMinor) throw new Error('Reference already identifies another grant');\n await User.updateOne({ _id: accountId }, { $inc: { creditMinor: amountMinor } }, { session });\n return;" + } + ] + }, + { + "id": "customer-can-grant-credit", + "desc": "Customer authentication is accepted without staff authorization.", + "scenario": "tracks/ecommerce/scenarios/progression-store-credit.json", + "targets": [ + "ecommerce.spec.store-credit.production-753.753a" + ], + "file": "server/src/credit.ts", + "edits": [ + { + "find": " app.post('/api/staff/credit', auth, staff, async (req, res) => {", + "replace": " app.post('/api/staff/credit', auth, async (req, res) => {" + } + ] + }, + { + "id": "credit-checkout-retains-purchased-cart", + "desc": "A second checkout can reuse the purchased cart and create another order.", + "scenario": "tracks/ecommerce/scenarios/progression-store-credit.json", + "targets": [ + "ecommerce.spec.store-credit.production-754.754a" + ], + "file": "server/src/credit.ts", + "edits": [ + { + "find": " cart.items = cart.items.filter(line => line.reservationExpiresAt && line.reservationExpiresAt <= now) as any;", + "replace": " // mutant: purchased cart lines remain" + } + ] + }, + { + "id": "split-refund-does-not-restore-credit", + "desc": "The refund is recorded but its original wallet credit is not restored.", + "scenario": "tracks/ecommerce/scenarios/progression-split-tender-refunds.json", + "targets": [ + "ecommerce.feature.split-tender-refunds.split-tender-refunds-751.751a" + ], + "file": "server/src/progression.ts", + "edits": [ + { + "find": " await refundCredit(order, session);", + "replace": " // mutant: omit wallet restoration" + } + ] + }, + { + "id": "split-refund-duplicates-credit", + "desc": "A refund credits the wallet twice while recording one refund.", + "scenario": "tracks/ecommerce/scenarios/progression-split-tender-refunds.json", + "targets": [ + "ecommerce.spec.split-tender-refunds.production-756.756a" + ], + "file": "server/src/credit.ts", + "edits": [ + { + "find": "{ $inc: { creditMinor: delta } }, { session });", + "replace": "{ $inc: { creditMinor: delta * 2 } }, { session });" + } + ] + }, + { + "id": "subscription-skips-due-purchase", + "desc": "Due deliveries are recorded as skipped although stock is available.", + "scenario": "tracks/ecommerce/scenarios/progression-subscriptions.json", + "targets": [ + "ecommerce.feature.subscriptions.subscriptions-760.760a" + ], + "file": "server/src/subscriptions.ts", + "edits": [ + { + "find": " const allocation = await reserveStock(row.itemId, row.quantity, session);", + "replace": " const allocation = row.quantity < 0 ? await reserveStock(row.itemId, row.quantity, session) : null;" + } + ] + }, + { + "id": "subscription-allows-foreign-cancellation", + "desc": "A customer can cancel another customer subscription.", + "scenario": "tracks/ecommerce/scenarios/progression-subscriptions.json", + "targets": [ + "ecommerce.spec.subscriptions.production-762.762a" + ], + "file": "server/src/subscriptions.ts", + "edits": [ + { + "find": " if (!row || String(row.userId) !== String((req as any).user._id)) return false;", + "replace": " if (!row) return false;" + } + ] + }, + { + "id": "subscription-pause-is-not-recorded", + "desc": "Pause acknowledges the request but the subscription remains active.", + "scenario": "tracks/ecommerce/scenarios/progression-subscriptions.json", + "targets": [ + "ecommerce.spec.subscriptions.production-763.763a" + ], + "file": "server/src/subscriptions.ts", + "edits": [ + { + "find": " row.status = 'paused'; row.pausedAt = new Date();", + "replace": " row.status = 'active'; row.pausedAt = new Date();" + } + ] + }, + { + "id": "credit-balance-is-cleared-at-startup", + "desc": "Restart clears an issued wallet balance while leaving accounts present.", + "file": "server/src/index.ts", + "scenario": "tracks/ecommerce/scenarios/progression-store-credit.json", + "targets": [ + "ecommerce.spec.store-credit.production-755.755a" + ], + "edits": [ + { + "find": " await seed();", + "replace": " await seed();\n await User.updateMany({}, { $set: { creditMinor: 0 } });" + } + ] + }, + { + "id": "pending-subscriptions-are-cleared-at-startup", + "desc": "Restart erases pending subscription work while preserving ordinary timer execution.", + "file": "server/src/index.ts", + "scenario": "tracks/ecommerce/scenarios/progression-subscriptions.json", + "targets": [ + "ecommerce.spec.subscriptions.production-761.761a" + ], + "edits": [ + { + "find": " await seed();", + "replace": " await seed();\n await mongoose.connection.collection(\"purchasesubscriptions\").deleteMany({ status: \"active\" });" + } + ] + }, + { + "id": "bundle-definition-loses-component-quantity", + "scenario": "tracks/ecommerce/scenarios/progression-product-bundles.json", + "targets": [ + "ecommerce.feature.product-bundles.product-bundles.740a" + ], + "desc": "definition loses component quantity", + "file": "server/src/bundles.ts", + "edits": [ + { + "find": "quantity: component.quantity });", + "replace": "quantity: 1 });" + } + ] + }, + { + "id": "bundle-catalog-write-allows-customers", + "scenario": "tracks/ecommerce/scenarios/progression-product-bundles.json", + "targets": [ + "ecommerce.spec.bundle-integrity.bundle-743.743a" + ], + "desc": "catalog write allows customers", + "file": "server/src/bundles.ts", + "edits": [ + { + "find": "if (!actor.isAdmin && !actor.roles?.includes('catalog'))", + "replace": "if (false)" + } + ] + }, + { + "id": "bundle-checkout-price-not-snapshot", + "scenario": "tracks/ecommerce/scenarios/progression-bundle-checkout.json", + "targets": [ + "ecommerce.feature.bundle-checkout.bundle-checkout.741a" + ], + "desc": "checkout price not snapshot", + "file": "server/src/bundles.ts", + "edits": [ + { + "find": "bundlePrice: bundle.price,", + "replace": "bundlePrice: bundle.price + 1," + } + ] + }, + { + "id": "bundle-expiry-does-not-release-components", + "scenario": "tracks/ecommerce/scenarios/progression-bundle-checkout.json", + "targets": [ + "ecommerce.spec.bundle-integrity.bundle-746.746a" + ], + "desc": "expiry does not release components", + "file": "server/src/bundles.ts", + "edits": [ + { + "find": "await releaseBundle(line.componentAllocations as Allocation[], session);\n line.componentAllocations = [] as any;", + "replace": "line.componentAllocations = [] as any; // mutant: component holds leak" + } + ] + }, + { + "id": "bundle-return-loses-original-components", + "scenario": "tracks/ecommerce/scenarios/progression-bundle-returns.json", + "targets": [ + "ecommerce.feature.bundle-returns.bundle-returns.742a" + ], + "desc": "return loses original components", + "file": "server/src/bundles.ts", + "edits": [ + { + "find": "for (const line of bundles) { await releaseBundle(line.componentAllocations as Allocation[], session); line.returned = true; }", + "replace": "for (const line of bundles) { line.returned = true; }" + } + ] + }, + { + "id": "bundle-return-replay-restocks-again", + "scenario": "tracks/ecommerce/scenarios/progression-bundle-returns.json", + "targets": [ + "ecommerce.spec.bundle-integrity.bundle-742.742b" + ], + "desc": "return replay restocks again", + "file": "server/src/bundles.ts", + "edits": [ + { + "find": "line.isBundle && !line.returned", + "replace": "line.isBundle" + } + ] + }, + { + "id": "bundle-return-crosses-account-boundary", + "scenario": "tracks/ecommerce/scenarios/progression-bundle-returns.json", + "targets": [ + "ecommerce.spec.bundle-integrity.bundle-748.748a" + ], + "desc": "return crosses account boundary", + "file": "server/src/bundles.ts", + "edits": [ + { + "find": "{ _id: req.params.orderId, userId, status: { $in: ['shipped', 'delivered'] } }", + "replace": "{ _id: req.params.orderId, status: { $in: ['shipped', 'delivered'] } }" + } + ] + }, + { + "id": "bundle-components-can-overdraw", + "scenario": "tracks/ecommerce/scenarios/progression-bundle-checkout.json", + "targets": [ + "ecommerce.spec.bundle-integrity.bundle-744.744a", + "ecommerce.spec.bundle-integrity.bundle-745.745a" + ], + "desc": "components can overdraw", + "file": "server/src/stock-reservations.ts", + "edits": [ + { + "find": "{ item_id: itemId, quantity: { $gte: 1 } }", + "replace": "{ item_id: itemId }" + } + ] + }, + { + "id": "bundle-checkout-reuses-reservation", + "scenario": "tracks/ecommerce/scenarios/progression-bundle-checkout.json", + "targets": [ + "ecommerce.spec.bundle-integrity.bundle-747.747a" + ], + "desc": "checkout reuses reservation", + "file": "server/src/credit.ts", + "edits": [ + { + "find": "cart.items = cart.items.filter(line => line.reservationExpiresAt && line.reservationExpiresAt <= now) as any;", + "replace": "// mutant: active cart survives checkout" + } + ] + }, + { + "id": "return-after-support-refund-is-blocked", + "scenario": "tracks/ecommerce/scenarios/progression-support-return-interaction.json", + "targets": [ + "ecommerce.feature.split-tender-refunds.return-refund-interaction.757a" + ], + "desc": "Reject a valid physical return after a financial refund.", + "file": "server/src/index.ts", + "edits": [ + { + "find": " if (!line || line.returned) throw new Error('No returnable item found');", + "replace": " if (!line || line.returned || value.refundTotal > 0) throw new Error('No returnable item found');" + } + ] + }, + { + "id": "support-refund-after-return-pays-twice", + "scenario": "tracks/ecommerce/scenarios/progression-support-return-interaction.json", + "targets": [ + "ecommerce.feature.split-tender-refunds.return-refund-interaction.757b" + ], + "desc": "Pay the full order again after a physical return.", + "file": "server/src/progression.ts", + "edits": [ + { + "find": " order.refundTotal = order.total;", + "replace": " order.refundTotal += order.total;" + } + ] + }, + { + "id": "support-history-leaks-to-signed-out-visitors", + "scenario": "tracks/ecommerce/scenarios/progression-support-history.json", + "targets": [ + "ecommerce.spec.access-control.support-history-logout.612d" + ], + "desc": "Disclose support tickets to signed-out visitors while leaving signed-in ownership filtering unchanged.", + "file": "server/src/progression.ts", + "edits": [ + { + "find": "const ticketFilter = isStaff ? {} : user ? { userId: user._id } : { _id: null };", + "replace": "const ticketFilter = isStaff ? {} : user ? { userId: user._id } : {};" + } + ] + }, + { + "id": "checkout-crash-integrity", + "scenario": "tracks/ecommerce/scenarios/progression-checkout-crash.json", + "targets": [ + "ecommerce.spec.state-durability.checkout-crash-integrity.910a" + ], + "desc": "A lifecycle callback changes a prepared or cleared cart to quantity two, leaving neither a legal rollback nor a complete checkout.", + "file": "server/src/index.ts", + "edits": [ + { + "find": " await initializeOrderData(mongoose.connection);", + "replace": " await initializeOrderData(mongoose.connection);\n for (const cart of await Cart.find()) { const order = await Order.findOne({ userId: cart.userId }); if (order?.items[0]) await Cart.updateOne({ _id: cart._id }, { $set: { items: [{ itemId: order.items[0].itemId, quantity: 2 }] } }); }" + } + ] + }, + { + "id": "checkout-crash-durability", + "scenario": "tracks/ecommerce/scenarios/progression-checkout-crash.json", + "targets": [ + "ecommerce.spec.state-durability.checkout-crash-durability.910b" + ], + "desc": "A lifecycle callback corrupts earlier order totals. The unchanged prepared snapshots and acknowledged baseline must expose the damage.", + "file": "server/src/index.ts", + "edits": [ + { + "find": " await initializeOrderData(mongoose.connection);", + "replace": " await initializeOrderData(mongoose.connection);\n await Order.updateMany({}, { $set: { total: 0 } });" + } + ] + }, + { + "id": "review-script-unsafe-render", + "scenario": "tracks/ecommerce/scenarios/progression-review-script.json", + "targets": [ + "ecommerce.progression.review-access-specifications.stored-review-script.9180a" + ], + "desc": "Render stored review text as HTML so it executes in another customer session.", + "file": "client/src/App.tsx", + "edits": [ + { + "find": "
{r.comment}
", + "replace": "
" + } + ] + }, + { + "id": "review-script-reject-all", + "scenario": "tracks/ecommerce/scenarios/progression-review-script.json", + "targets": [ + "ecommerce.progression.review-access-specifications.stored-review-script.9180a" + ], + "desc": "Reject all nonempty reviews, including the required benign review; absence of script is insufficient.", + "file": "server/src/index.ts", + "edits": [ + { + "find": "const { rating, comment } = req.body || {};", + "replace": "const { rating, comment } = req.body || {};\n if (String(comment).length > 0) { res.status(400).json({ error: \"Review rejected\" }); return; }" + } + ] + }, + { + "id": "review-owner-trust-username", + "scenario": "tracks/ecommerce/scenarios/progression-review-access.json", + "targets": [ + "ecommerce.progression.review-access-specifications.review-eligibility-direct.618a" + ], + "desc": "Trust the submitted buyer username instead of the authenticated caller.", + "file": "server/src/index.ts", + "edits": [ + { + "find": "const user = (req as any).user;\n const hasPurchased = await Order.exists", + "replace": "const user = req.body?.username ? await User.findOne({ username: req.body.username }) : (req as any).user;\n const hasPurchased = await Order.exists" + } + ] + }, + { + "id": "review-owner-deny-after-write", + "scenario": "tracks/ecommerce/scenarios/progression-review-access.json", + "targets": [ + "ecommerce.progression.review-access-specifications.review-eligibility-direct.618a" + ], + "desc": "Replace the buyer review under a forged username, then return a refusal.", + "file": "server/src/index.ts", + "edits": [ + { + "find": "const user = (req as any).user;\n const hasPurchased = await Order.exists", + "replace": "const user = req.body?.username ? await User.findOne({ username: req.body.username }) : (req as any).user;\n const hasPurchased = await Order.exists" + }, + { + "find": "await broadcastReviews(String(itemId));", + "replace": "if (req.body?.username) return res.status(403).json({ error: \"Refused after write\" });\n await broadcastReviews(String(itemId));" + } + ] + }, + { + "id": "review-owner-reject-all", + "scenario": "tracks/ecommerce/scenarios/progression-review-access.json", + "targets": [ + "ecommerce.progression.review-access-specifications.review-eligibility-direct.618a" + ], + "desc": "Reject the legitimate buyer review as well as unauthorized reviews.", + "file": "server/src/index.ts", + "edits": [ + { + "find": "const { rating, comment } = req.body || {};", + "replace": "const { rating, comment } = req.body || {};\n if (String(comment).length > 0) { res.status(403).json({ error: \"Reject all reviews\" }); return; }" + } + ] + }, + { + "id": "password-verification-truncates-utf8", + "scenario": "tracks/ecommerce/scenarios/01-account-password.json", + "targets": [ + "ecommerce.feature.accounts.accounts.1c" + ], + "desc": "Hash and verify only the first 72 UTF-8 bytes, accepting a different password suffix.", + "file": "server/src/auth.ts", + "edits": [ + { + "find": "scrypt(password, salt, 64,", + "replace": "scrypt(Buffer.from(password).subarray(0, 72), salt, 64," + } + ] + }, + { + "id": "password-verification-rejects-every-login", + "scenario": "tracks/ecommerce/scenarios/01-account-password.json", + "targets": [ + "ecommerce.feature.accounts.accounts.1c" + ], + "desc": "Refuse even a correct password; refusal alone must not earn credit.", + "file": "server/src/auth.ts", + "edits": [ + { + "find": "return crypto.timingSafeEqual", + "replace": "return false && crypto.timingSafeEqual" + } + ] + } + ] +} diff --git a/tools/stack-bench/grader/mutations/postgres-ecommerce.json b/tools/stack-bench/grader/mutations/postgres-ecommerce.json new file mode 100644 index 00000000000..d33d22c7123 --- /dev/null +++ b/tools/stack-bench/grader/mutations/postgres-ecommerce.json @@ -0,0 +1,2679 @@ +{ + "schemaVersion": 3, + "fixtureSha256": "600b7fc1fe4efebe8fa7713211aa4aab788c51994519debd74696ba761d2d57a", + "backend": "postgres", + "track": "ecommerce", + "note": "Mutation definitions for the PostgreSQL ecommerce reference.", + "mutations": [ + { + "id": "recommendation-dismissal-lost-on-restart", + "scenario": "tracks/ecommerce/scenarios/progression-recommendation-feedback.json", + "targets": [ + "ecommerce.spec.state-durability.recommendation-feedback-restart.504c" + ], + "desc": "Erase saved recommendation dismissals when the application starts again.", + "file": "server/src/index.ts", + "edits": [ + { + "find": " await initializeProgressionSchema(pool);", + "replace": " await initializeProgressionSchema(pool);\n await pool.query('DELETE FROM recommendation_dismissal');" + } + ] + }, + { + "id": "pending-order-item-return-accepted", + "scenario": "tracks/ecommerce/scenarios/progression-order-return-boundary.json", + "targets": [ + "ecommerce.returns-pricing.cancellation-and-return.3f" + ], + "desc": "Accept a pending order return and restore its stock before shipment.", + "file": "server/src/index.ts", + "edits": [ + { + "find": "if (!['shipped', 'delivered'].includes(orderRow.rows[0].status)) {", + "replace": "if (!['pending', 'shipped', 'delivered'].includes(orderRow.rows[0].status)) {" + } + ] + }, + { + "id": "staff-admin-access-survives-role-removal", + "scenario": "tracks/ecommerce/scenarios/progression-staff-roles.json", + "targets": [ + "ecommerce.spec.access-control.staff-role-revocation.621d" + ], + "desc": "Keep administrator access after changing the assigned role back to staff.", + "file": "server/src/progression.ts", + "edits": [ + { + "find": "is_admin = ($1 = 'admin')", + "replace": "is_admin = (is_admin OR $1 = 'admin')" + } + ] + }, + { + "id": "shipping-counts-sale-twice", + "scenario": "tracks/ecommerce/scenarios/progression-shipping-accounting.json", + "targets": [ + "ecommerce.inventory-operations.shipping-accounting.202e" + ], + "desc": "Shipping succeeds but doubles the completed sale value in authoritative revenue.", + "file": "server/src/index.ts", + "edits": [ + { + "find": "`UPDATE orders SET status = 'shipped', shipped_at = now()\n WHERE id = $1 AND status = 'pending' RETURNING account_id`", + "replace": "`UPDATE orders SET status = 'shipped', shipped_at = now(), total = total * 2\n WHERE id = $1 AND status = 'pending' RETURNING account_id`" + } + ] + }, + { + "id": "signup-ui-does-not-enter-created-account", + "scenario": "tracks/ecommerce/scenarios/01-account-create.json", + "targets": [ + "ecommerce.feature.accounts.accounts.1a" + ], + "desc": "Create the account successfully but discard the returned signed-in identity in the client.", + "file": "client/src/App.tsx", + "edits": [ + { + "find": " const r = await api<{ account: Account }>(\"/api/auth/signup\", {\n method: \"POST\",\n body: JSON.stringify({ username, password }),\n });\n setAccount(r.account);", + "replace": " const r = await api<{ account: Account }>(\"/api/auth/signup\", {\n method: \"POST\",\n body: JSON.stringify({ username, password }),\n });\n void r;\n setAccount(null);" + } + ] + }, + { + "id": "duplicate-signup-authenticates-existing-account", + "scenario": "tracks/ecommerce/scenarios/01-account-duplicate.json", + "targets": [ + "ecommerce.feature.accounts.accounts.1b" + ], + "desc": "Treat a duplicate signup as a successful session for the pre-existing account.", + "file": "server/src/index.ts", + "edits": [ + { + "find": " if (existing.length > 0) {\n res.status(409).json({ error: \"username already taken\" });\n return;\n }", + "replace": " if (existing.length > 0) {\n const token = newToken();\n await db.insert(session).values({ id: token, accountId: existing[0].id });\n res.cookie(\"sid\", token, { httpOnly: true, sameSite: \"lax\", path: \"/\" });\n res.json({ account: { id: existing[0].id, username, isAdmin: false, isStaff: false } });\n return;\n }" + } + ] + }, + { + "id": "signin-skips-password-verification", + "scenario": "tracks/ecommerce/scenarios/01-account-password.json", + "targets": [ + "ecommerce.feature.accounts.accounts.1c" + ], + "desc": "Accept an existing account regardless of its password; valid login remains possible.", + "file": "server/src/index.ts", + "edits": [ + { + "find": " if (rows.length === 0 || !(await verifyPassword(password, rows[0].passwordHash))) {", + "replace": " if (rows.length === 0) {" + } + ] + }, + { + "id": "correct-signin-is-refused", + "scenario": "tracks/ecommerce/scenarios/01-account-signout.json", + "targets": [ + "ecommerce.feature.accounts.accounts.1d" + ], + "desc": "Preserve wrong-password refusal but reject an otherwise valid sign-in, preventing a signed-out account from returning.", + "file": "server/src/index.ts", + "edits": [ + { + "find": " const acc = rows[0];\n const token = newToken();", + "replace": " const acc = rows[0];\n if (username === acc.username) {\n res.status(401).json({ error: \"sign in is unavailable\" });\n return;\n }\n const token = newToken();" + } + ] + }, + { + "id": "reload-discards-session-identity", + "scenario": "tracks/ecommerce/scenarios/01-account-reload.json", + "targets": [ + "ecommerce.spec.state-durability.session-reload.1e" + ], + "desc": "Ignore the authenticated identity returned during initial page hydration.", + "file": "client/src/App.tsx", + "edits": [ + { + "find": " setAccount(me.account);", + "replace": " setAccount(null);" + } + ] + }, + { + "id": "purchase-does-not-broadcast-ranking", + "scenario": "tracks/ecommerce/scenarios/01-core.json", + "targets": [ + "ecommerce.spec.live-state.ranking.2c" + ], + "desc": "Commit the purchase but omit the catalog broadcast that updates already-open rankings.", + "file": "server/src/index.ts", + "edits": [ + { + "find": " lastCatalogJson = json;\n io.emit(\"items:update\", { items: catalog });", + "replace": " lastCatalogJson = json;\n // mutant: changed catalog state is not broadcast" + } + ] + }, + { + "id": "signed-out-purchase-uses-default-account", + "scenario": "tracks/ecommerce/scenarios/progression-signed-out-purchase.json", + "targets": [ + "ecommerce.spec.access-control.signed-out-purchase.3a" + ], + "desc": "Expose purchase controls to guests and let the purchase route charge the first stored account when no caller is authenticated.", + "file": "client/src/App.tsx", + "edits": [ + { + "find": " const canBuy = !!account && !account.isAdmin && !account.isStaff;", + "replace": " const canBuy = !account || (!account.isAdmin && !account.isStaff);" + }, + { + "file": "server/src/index.ts", + "find": " \"/api/items/:id/buy\",\n requireAuth,\n asyncHandler(async (req, res) => {\n const itemId = Number(req.params.id);\n const accountId = req.account!.id;", + "replace": " \"/api/items/:id/buy\",\n asyncHandler(async (req, res) => {\n const itemId = Number(req.params.id);\n const accountId = req.account?.id ?? (await pool.query(`SELECT id FROM account ORDER BY id LIMIT 1`)).rows[0].id;" + } + ] + }, + { + "id": "purchase-stock-change-is-not-broadcast--01-buying", + "scenario": "tracks/ecommerce/scenarios/01-buying.json", + "targets": [ + "ecommerce.spec.live-state.purchase-stock.3b" + ], + "desc": "Commit purchases without broadcasting their stock changes, breaking live stock and sold-out visibility.", + "file": "server/src/index.ts", + "edits": [ + { + "find": " lastCatalogJson = json;\n io.emit(\"items:update\", { items: catalog });", + "replace": " lastCatalogJson = json;\n // mutant: changed stock is not broadcast" + } + ] + }, + { + "id": "purchase-stock-change-is-not-broadcast--stock-limit", + "scenario": "tracks/ecommerce/scenarios/progression-stock-limit.json", + "targets": [ + "ecommerce.spec.concurrency-safety.stock-limit.3d" + ], + "desc": "Commit purchases without broadcasting their stock changes, breaking live stock and sold-out visibility.", + "file": "server/src/index.ts", + "edits": [ + { + "find": " lastCatalogJson = json;\n io.emit(\"items:update\", { items: catalog });", + "replace": " lastCatalogJson = json;\n // mutant: changed stock is not broadcast" + } + ] + }, + { + "id": "restock-race-records-wrong-order-total", + "scenario": "tracks/ecommerce/scenarios/01-restock-race.json", + "targets": [ + "ecommerce.spec.concurrency-safety.restock-race.202a" + ], + "desc": "Purchases preserve stock and visible order counts but record the wrong booked total. Native mixed-race reconciliation must reject them.", + "file": "server/src/index.ts", + "edits": [ + { + "find": " [accountId, price]\n );", + "replace": " [accountId, Number(price) + 1]\n );" + } + ] + }, + { + "id": "direct-purchase-order-total-is-offset", + "scenario": "tracks/ecommerce/scenarios/progression-purchasing.json", + "targets": [ + "ecommerce.feature.purchasing.purchase-order.3c" + ], + "desc": "Record a direct purchase one dollar above the stored price.", + "file": "server/src/index.ts", + "edits": [ + { + "find": " [accountId, price]\n );", + "replace": " [accountId, Number(price) + 1]\n );" + } + ] + }, + { + "id": "reload-hydrates-an-empty-cart", + "scenario": "tracks/ecommerce/scenarios/01-cart.json", + "targets": [ + "ecommerce.spec.state-durability.cart-reload.4b" + ], + "desc": "Return an empty cart from both reload hydration paths while preserving later live cart broadcasts.", + "file": "server/src/index.ts", + "edits": [ + { + "find": " const state = await buildCartState(req.account!.id);\n res.json(state);", + "replace": " await buildCartState(req.account!.id);\n res.json({ items: [], total: 0 });" + }, + { + "find": " const cartState = await buildCartState(acc.id);\n socket.emit(\"cart:update\", cartState);", + "replace": " await buildCartState(acc.id);\n socket.emit(\"cart:update\", { items: [], total: 0 });" + } + ] + }, + { + "id": "signed-out-visitors-do-not-see-reviews", + "scenario": "tracks/ecommerce/scenarios/01-review-visibility.json", + "targets": [ + "ecommerce.feature.reviews.reviews.6a" + ], + "desc": "Hide an item's reviews whenever the viewer is signed out.", + "file": "client/src/App.tsx", + "edits": [ + { + "find": " {reviews.length === 0 ? (", + "replace": " {!account || reviews.length === 0 ? (" + } + ] + }, + { + "id": "review-average-update-is-not-broadcast", + "scenario": "tracks/ecommerce/scenarios/01-review-rating-live.json", + "targets": [ + "ecommerce.spec.live-state.rating.6c" + ], + "desc": "Return the new average to the submitter but omit the live review update to other viewers.", + "file": "server/src/index.ts", + "edits": [ + { + "find": " io.emit(\"review:update\", { itemId, reviews, average });", + "replace": " // mutant: other open review views do not receive the new average" + } + ] + }, + { + "id": "admin-warehouse-view-drops-one-location", + "scenario": "tracks/ecommerce/scenarios/01-warehouse-admin-staff.json", + "targets": [ + "ecommerce.feature.warehouse-admin.warehouse-view.7b" + ], + "desc": "Render only 23 of the 24 item-by-warehouse stock locations.", + "file": "client/src/App.tsx", + "edits": [ + { + "find": " {admin.locations.map((loc) => {", + "replace": " {admin.locations.slice(0, 23).map((loc) => {" + } + ] + }, + { + "id": "unauthenticated-direct-purchase-uses-default-account", + "scenario": "tracks/ecommerce/scenarios/01-purchase-session.json", + "targets": [ + "ecommerce.spec.access-control.purchase-session.101a" + ], + "desc": "Remove purchase authentication and attribute unauthenticated requests to a default account.", + "file": "server/src/index.ts", + "edits": [ + { + "find": " \"/api/items/:id/buy\",\n requireAuth,", + "replace": " \"/api/items/:id/buy\"," + }, + { + "find": " const itemId = Number(req.params.id);\n const accountId = req.account!.id;\n\n const client = await pool.connect();", + "replace": " const itemId = Number(req.params.id);\n const accountId = req.account?.id ?? 1;\n\n const client = await pool.connect();" + } + ] + }, + { + "id": "direct-purchase-is-attributed-to-previous-account", + "scenario": "tracks/ecommerce/scenarios/01-purchase-attribution.json", + "targets": [ + "ecommerce.spec.access-control.purchase-attribution.102a" + ], + "desc": "Create the direct-purchase order for the preceding account id rather than the authenticated caller.", + "file": "server/src/index.ts", + "edits": [ + { + "find": " const itemId = Number(req.params.id);\n const accountId = req.account!.id;\n\n const client = await pool.connect();", + "replace": " const itemId = Number(req.params.id);\n const accountId = req.account!.id - 1;\n\n const client = await pool.connect();" + } + ] + }, + { + "id": "direct-purchase-uses-constant-price", + "scenario": "tracks/ecommerce/scenarios/01-server-price.json", + "targets": [ + "ecommerce.spec.transactional-integrity.server-price.104a" + ], + "desc": "Create a direct-purchase order at a hard-coded price instead of the current stored price.", + "file": "server/src/index.ts", + "edits": [ + { + "find": " [accountId, price]\n );", + "replace": " [accountId, \"1.00\"]\n );" + } + ] + }, + { + "id": "account-state-reload-discards-session", + "scenario": "tracks/ecommerce/scenarios/progression-account-state-reload.json", + "targets": [ + "ecommerce.spec.state-durability.account-state-recovery.105a" + ], + "desc": "Discard the authenticated account during reload hydration, making its cart and orders unavailable.", + "file": "client/src/App.tsx", + "edits": [ + { + "find": " setAccount(me.account);", + "replace": " setAccount(null);" + } + ] + }, + { + "id": "offline-event-clears-account-state", + "scenario": "tracks/ecommerce/scenarios/progression-account-state-reconnect.json", + "targets": [ + "ecommerce.spec.state-durability.account-state-recovery.105b" + ], + "desc": "Treat a temporary offline event as a sign-out and clear the account and cart state.", + "file": "client/src/App.tsx", + "edits": [ + { + "find": " useEffect(() => {\n const socket = io({ path: \"/socket.io\" });", + "replace": " useEffect(() => {\n const clearAccountOffline = () => {\n setAccount(null);\n setCart({ items: [], total: 0 });\n };\n window.addEventListener(\"offline\", clearAccountOffline, { once: true });\n const socket = io({ path: \"/socket.io\" });" + } + ] + }, + { + "id": "purchase-does-not-decrement-warehouse-stock", + "scenario": "tracks/ecommerce/scenarios/progression-books-balance.json", + "targets": [ + "ecommerce.spec.transactional-integrity.books-balance.107b" + ], + "desc": "Create purchase orders without decrementing their selected warehouse stock row.", + "file": "server/src/index.ts", + "edits": [ + { + "find": " UPDATE stock s SET quantity = quantity - 1\n FROM target t", + "replace": " UPDATE stock s SET quantity = quantity\n FROM target t" + } + ] + }, + { + "id": "review-route-skips-purchase-eligibility", + "scenario": "tracks/ecommerce/scenarios/01-review-eligibility.json", + "targets": [ + "ecommerce.spec.access-control.review-eligibility.108a" + ], + "desc": "Allow review creation even when the caller has never purchased the item.", + "file": "server/src/index.ts", + "edits": [ + { + "find": " if (purchased.rowCount === 0) {", + "replace": " if (false && purchased.rowCount === 0) {" + } + ] + }, + { + "id": "only-shipped-orders-earn-review-eligibility", + "scenario": "tracks/ecommerce/scenarios/01-review-eligibility.json", + "targets": [ + "ecommerce.spec.access-control.review-eligibility.108b", + "ecommerce.spec.access-control.review-eligibility.108a" + ], + "desc": "Incorrectly require an order to be shipped before its buyer may review the item. The same restriction also rejects the required successful buyer control in 108a; it does not independently test non-buyer denial.", + "file": "server/src/index.ts", + "edits": [ + { + "find": " WHERE o.account_id = $1 AND oi.item_id = $2 LIMIT 1`,", + "replace": " WHERE o.account_id = $1 AND oi.item_id = $2 AND o.status = 'shipped' LIMIT 1`," + } + ] + }, + { + "id": "cart-update-accepts-negative-quantity", + "scenario": "tracks/ecommerce/scenarios/01-cart-boundary.json", + "targets": [ + "ecommerce.spec.access-control.cart-boundary.109b" + ], + "desc": "Accept a negative cart quantity update and persist it instead of refusing the named action.", + "file": "server/src/index.ts", + "edits": [ + { + "find": " if (!Number.isInteger(quantity) || quantity < 1) {", + "replace": " if (!Number.isInteger(quantity)) {" + } + ] + }, + { + "id": "oversell-no-row-lock", + "scenario": "tracks/ecommerce/scenarios/01-last-unit.json", + "targets": [ + "ecommerce.spec.concurrency-safety.last-unit.201a", + "ecommerce.spec.concurrency-safety.last-unit.201b", + "ecommerce.spec.concurrency-safety.last-unit.201c" + ], + "desc": "Drop the row lock so simultaneous buyers can select the same remaining units.", + "file": "server/src/index.ts", + "edits": [ + { + "find": " FOR UPDATE\n LIMIT 1", + "replace": " LIMIT 1" + } + ] + }, + { + "id": "purchase-read-write-loses-concurrent-stock", + "scenario": "tracks/ecommerce/scenarios/01-restock-race.json", + "targets": [ + "ecommerce.spec.concurrency-safety.restock-race.202a" + ], + "desc": "Replace atomic stock reservation with an unlocked read and absolute write. A fixed pause widens scheduling overlap; serial purchases and restocks retain their stock effects. Concurrent reservations or restocking can lose updates.", + "file": "server/src/index.ts", + "edits": [ + { + "find": " const decrement = await client.query(\n `WITH target AS (\n SELECT item_id, warehouse_id FROM stock\n WHERE item_id = $1 AND quantity > 0\n ORDER BY warehouse_id\n FOR UPDATE\n LIMIT 1\n )\n UPDATE stock s SET quantity = quantity - 1\n FROM target t\n WHERE s.item_id = t.item_id AND s.warehouse_id = t.warehouse_id\n RETURNING s.item_id, s.warehouse_id`,\n [itemId]\n );\n", + "replace": " const snapshot = await client.query(\n `SELECT item_id, warehouse_id, quantity FROM stock\n WHERE item_id = $1 AND quantity > 0 ORDER BY warehouse_id LIMIT 1`, [itemId]\n );\n // Mutant: widen the unlocked read/write window without changing serial behavior.\n await new Promise(resolve => setTimeout(resolve, 500));\n const decrement = snapshot.rowCount === 0 ? snapshot : await client.query(\n `UPDATE stock SET quantity = $3 WHERE item_id = $1 AND warehouse_id = $2\n RETURNING item_id, warehouse_id`,\n [itemId, snapshot.rows[0].warehouse_id, snapshot.rows[0].quantity - 1]\n );\n" + } + ] + }, + { + "id": "external-stock-polling-disabled", + "scenario": "tracks/ecommerce/scenarios/01-external-live-sync.json", + "targets": [ + "ecommerce.spec.external-data-sync.external-stock.901a" + ], + "desc": "Stop reconciling direct database changes while the server remains online.", + "file": "server/src/index.ts", + "edits": [ + { + "find": " broadcastCatalog().catch((err) => console.error(\"poll broadcast failed\", err));", + "replace": " // mutant: direct database catalog changes are never reconciled" + } + ] + }, + { + "id": "server-restart-does-not-resynchronize-catalog", + "scenario": "tracks/ecommerce/scenarios/01-external-server-restart-sync.json", + "targets": [ + "ecommerce.spec.external-data-sync.external-stock.901c" + ], + "desc": "After a server restart, omit both connection-time catalog hydration and periodic authoritative reconciliation.", + "file": "server/src/index.ts", + "edits": [ + { + "find": " const catalog = await buildCatalog();\n socket.emit(\"items:update\", { items: catalog });", + "replace": " // mutant: reconnecting clients retain their pre-restart catalog" + }, + { + "find": " broadcastCatalog().catch((err) => console.error(\"poll broadcast failed\", err));", + "replace": " // mutant: restart recovery does not reconcile authoritative catalog state" + } + ] + }, + { + "id": "reconnect-does-not-send-current-catalog", + "scenario": "tracks/ecommerce/scenarios/01-external-reconnect-sync.json", + "targets": [ + "ecommerce.spec.external-data-sync.external-stock.901d" + ], + "desc": "Follow catalog changes until the browser goes offline, then ignore updates after restoration.", + "file": "client/src/App.tsx", + "edits": [ + { + "find": " const cartObservationRef = useRef(0);\n\n function applyCartResponse", + "replace": " const cartObservationRef = useRef(0);\n const acceptCatalogUpdates = useRef(true);\n useEffect(() => {\n const stopCatalogRecovery = () => { acceptCatalogUpdates.current = false; };\n window.addEventListener(\"offline\", stopCatalogRecovery);\n return () => window.removeEventListener(\"offline\", stopCatalogRecovery);\n }, []);\n\n function applyCartResponse" + }, + { + "find": " socket.on(\"items:update\", (payload: { items: Item[] }) => setItems(payload.items));", + "replace": " socket.on(\"items:update\", (payload: { items: Item[] }) => {\n if (acceptCatalogUpdates.current) setItems(payload.items);\n });" + } + ] + }, + { + "id": "open-review-list-ignores-live-update", + "scenario": "tracks/ecommerce/scenarios/progression-open-list-live.json", + "targets": [ + "ecommerce.spec.live-state.open-list.902a" + ], + "desc": "Ignore committed review updates in a detail view that is already open.", + "file": "client/src/App.tsx", + "edits": [ + { + "find": " setItemDetail({ reviews: payload.reviews, average: payload.average });", + "replace": " // mutant: the already-open review list ignores committed updates" + } + ] + }, + { + "id": "open-review-list-renders-each-review-twice", + "scenario": "tracks/ecommerce/scenarios/progression-open-list-live.json", + "targets": [ + "ecommerce.spec.live-state.open-list.902a" + ], + "desc": "Render every committed review twice in the already-open list.", + "file": "client/src/App.tsx", + "edits": [ + { + "find": " reviews.map((r) => (", + "replace": " [...reviews, ...reviews].map((r) => (" + } + ] + }, + { + "id": "cancel-does-not-restore-stock-feature", + "scenario": "tracks/ecommerce/scenarios/02-order-cancellation-core.json", + "targets": [ + "ecommerce.returns-pricing.cancellation-and-return.3a" + ], + "desc": "Cancellation commits but restores zero units to each recorded warehouse row.", + "file": "server/src/index.ts", + "edits": [ + { + "find": " [l.item_id, l.warehouse_id, l.quantity]\n );\n }\n await refundCredit(client, orderRow.rows[0]);\n await client.query(`UPDATE orders SET status = 'cancelled' WHERE id = $1`, [orderId]);", + "replace": " [l.item_id, l.warehouse_id, 0]\n );\n }\n await refundCredit(client, orderRow.rows[0]);\n await client.query(`UPDATE orders SET status = 'cancelled' WHERE id = $1`, [orderId]);" + } + ] + }, + { + "id": "cancellation-accounting-loses-stock-restoration", + "scenario": "tracks/ecommerce/scenarios/02-invariants.json", + "targets": [ + "ecommerce.returns-pricing.refund-accounting.203a" + ], + "desc": "Cancellation removes revenue and changes order status, but loses the original warehouse stock restoration. The native refund-accounting assertion must detect this.", + "file": "server/src/index.ts", + "edits": [ + { + "find": " [l.item_id, l.warehouse_id, l.quantity]\n );\n }\n await refundCredit(client, orderRow.rows[0]);\n await client.query(`UPDATE orders SET status = 'cancelled' WHERE id = $1`, [orderId]);", + "replace": " [l.item_id, l.warehouse_id, 0]\n );\n }\n await refundCredit(client, orderRow.rows[0]);\n await client.query(`UPDATE orders SET status = 'cancelled' WHERE id = $1`, [orderId]);" + } + ] + }, + { + "id": "cancel-does-not-restore-stock-fresh-client", + "scenario": "tracks/ecommerce/scenarios/02-self-contained.json", + "targets": [ + "ecommerce.inventory-operations.stock-conservation.202b", + "ecommerce.inventory-operations.stock-conservation.202c" + ], + "desc": "Cancellation commits but restores zero units, so a fresh client reads the persisted shortfall.", + "file": "server/src/index.ts", + "edits": [ + { + "find": " [l.item_id, l.warehouse_id, l.quantity]\n );\n }\n await refundCredit(client, orderRow.rows[0]);\n await client.query(`UPDATE orders SET status = 'cancelled' WHERE id = $1`, [orderId]);", + "replace": " [l.item_id, l.warehouse_id, 0]\n );\n }\n await refundCredit(client, orderRow.rows[0]);\n await client.query(`UPDATE orders SET status = 'cancelled' WHERE id = $1`, [orderId]);" + } + ] + }, + { + "id": "cancel-restores-stock-but-keeps-pending-status", + "scenario": "tracks/ecommerce/scenarios/02-order-cancellation-history.json", + "targets": [ + "ecommerce.returns-pricing.cancellation-and-return.3b" + ], + "desc": "Cancellation restores allocations but writes pending back to order history.", + "file": "server/src/index.ts", + "edits": [ + { + "find": "await client.query(`UPDATE orders SET status = 'cancelled' WHERE id = $1`, [orderId]);", + "replace": "await client.query(`UPDATE orders SET status = 'pending' WHERE id = $1`, [orderId]);" + } + ] + }, + { + "id": "operator-authorization-allows-customer-transfer", + "scenario": "tracks/ecommerce/scenarios/02-strengthened.json", + "targets": [ + "ecommerce.operations-access.operator-authorization.201a" + ], + "desc": "The transfer route replaces its administrator gate with ordinary authentication.", + "file": "server/src/index.ts", + "edits": [ + { + "find": "app.post(\n \"/api/admin/transfer\",\n requireAdmin,", + "replace": "app.post(\n \"/api/admin/transfer\",\n requireAuth," + } + ] + }, + { + "id": "customer-can-ship-order-direct-1-1", + "scenario": "tracks/ecommerce/scenarios/02-server-actions.json", + "targets": [ + "ecommerce.operations-access.operator-authorization.201c" + ], + "desc": "The shipping route replaces its staff gate with ordinary authentication.", + "file": "server/src/index.ts", + "edits": [ + { + "find": "app.post(\n \"/api/fulfilment/ship\",\n requireStaff,", + "replace": "app.post(\n \"/api/fulfilment/ship\",\n requireAuth," + } + ] + }, + { + "id": "customer-can-cancel-foreign-order-1-1", + "scenario": "tracks/ecommerce/scenarios/02-server-actions.json", + "targets": [ + "ecommerce.operations-access.order-owner.204a" + ], + "desc": "Cancellation retains authentication and pending-state validation but drops order ownership.", + "file": "server/src/index.ts", + "edits": [ + { + "find": "app.post(\n \"/api/orders/:id/cancel\",\n requireAuth,\n asyncHandler(async (req, res) => {\n const orderId = Number(req.params.id);\n const accountId = req.account!.id;\n const client = await pool.connect();\n try {\n await client.query(\"BEGIN\");\n const orderRow = await client.query(`SELECT * FROM orders WHERE id = $1 FOR UPDATE`, [orderId]);\n if (orderRow.rowCount === 0 || orderRow.rows[0].account_id !== accountId) {", + "replace": "app.post(\n \"/api/orders/:id/cancel\",\n requireAuth,\n asyncHandler(async (req, res) => {\n const orderId = Number(req.params.id);\n const accountId = req.account!.id;\n const client = await pool.connect();\n try {\n await client.query(\"BEGIN\");\n const orderRow = await client.query(`SELECT * FROM orders WHERE id = $1 FOR UPDATE`, [orderId]);\n if (orderRow.rowCount === 0) {" + } + ] + }, + { + "id": "queue-depth-lags-one-order", + "scenario": "tracks/ecommerce/scenarios/02-fulfilment-live.json", + "targets": [ + "ecommerce.operations-access.fulfilment-queue.1a" + ], + "desc": "The queue renders every order but its visible depth remains one behind.", + "file": "client/src/App.tsx", + "edits": [ + { + "find": "{queue.depth}", + "replace": "{Math.max(0, queue.depth - 1)}" + } + ] + }, + { + "id": "customer-sees-fulfilment-navigation", + "scenario": "tracks/ecommerce/scenarios/02-features.json", + "targets": [ + "ecommerce.operations-access.fulfilment-queue.1d" + ], + "desc": "Expose the protected staff area to signed-in customers, including its navigation and content.", + "file": "client/src/App.tsx", + "edits": [ + { + "find": " {account && (account.isStaff || account.isAdmin) && (\n
)}", + "replace": " )}" + } + ] + }, + { + "id": "purchase-does-not-broadcast-fulfilment-queue", + "scenario": "tracks/ecommerce/scenarios/02-fulfilment-live.json", + "targets": [ + "ecommerce.spec.live-state.fulfilment-queue.1a" + ], + "desc": "A direct purchase commits its pending order but omits the fulfilment queue broadcast, so an open staff queue never learns about the new order.", + "file": "server/src/index.ts", + "edits": [ + { + "find": " await broadcastCatalog();\n await broadcastOrders(accountId);\n await broadcastFulfilment();\n await broadcastRecommended(accountId);\n res.json({ ok: true });\n })\n);\n\n// ---------- cart routes ----------", + "replace": " await broadcastCatalog();\n await broadcastOrders(accountId);\n // mutant: the new pending order is not pushed to open fulfilment queues\n await broadcastRecommended(accountId);\n res.json({ ok: true });\n })\n);\n\n// ---------- cart routes ----------" + } + ] + }, + { + "id": "admin-state-change-is-not-broadcast", + "scenario": "tracks/ecommerce/scenarios/02-low-stock.json", + "targets": [ + "ecommerce.spec.live-state.inventory-dashboard.5a" + ], + "desc": "Changed admin dashboard state is never broadcast to open admin views, so a customer purchase that drops an item to ten units does not re-enter the low-stock list live.", + "file": "server/src/index.ts", + "edits": [ + { + "find": " lastAdminJson = adminJson;\n io.to(\"admin\").emit(\"admin:update\", adminState);", + "replace": " lastAdminJson = adminJson;\n // mutant: changed admin state is not broadcast" + } + ] + }, + { + "id": "admin-sockets-do-not-join-admin-room", + "scenario": "tracks/ecommerce/scenarios/02-operational-category-totals.json", + "targets": [ + "ecommerce.spec.live-state.sales-dashboard.5b" + ], + "desc": "Admin sockets receive their dashboard state on connection but never join the admin room, so a customer purchase does not update the open category totals live.", + "file": "server/src/index.ts", + "edits": [ + { + "find": " if (acc.isAdmin) socket.join(\"admin\");", + "replace": " // mutant: admin sockets never join the admin room" + } + ] + }, + { + "id": "transfer-overdraft-guard-skips-bulk-transfers", + "scenario": "tracks/ecommerce/scenarios/02-transfer-overdraw.json", + "targets": [ + "ecommerce.spec.transactional-integrity.stock-transfer-overdraw.2c" + ], + "desc": "The insufficient-stock guard is only evaluated for transfers under 1000 units, so a bulk transfer that overdraws the source warehouse commits instead of being refused.", + "file": "server/src/index.ts", + "edits": [ + { + "find": " if (available < qty) {", + "replace": " if (available < qty && qty < 1000) {" + } + ] + }, + { + "id": "transfer-does-not-publish-warehouse-totals", + "scenario": "tracks/ecommerce/scenarios/02-transfer-totals.json", + "targets": [ + "ecommerce.spec.live-state.stock-transfers.2b" + ], + "desc": "A transfer commits but answers with the pre-transfer admin snapshot and admin state is never broadcast, so the open warehouse totals do not move.", + "file": "server/src/index.ts", + "edits": [ + { + "find": " const client = await pool.connect();\n try {\n await client.query(\"BEGIN\");\n // Lock both warehouse rows", + "replace": " const state = await buildAdminState();\n const client = await pool.connect();\n try {\n await client.query(\"BEGIN\");\n // Lock both warehouse rows" + }, + { + "find": " await broadcastCatalog();\n const state = await buildAdminState();\n res.json(state);\n })\n);\n\napp.post(\n \"/api/admin/price\",", + "replace": " await broadcastCatalog();\n res.json(state);\n })\n);\n\napp.post(\n \"/api/admin/price\"," + }, + { + "find": " lastAdminJson = adminJson;\n io.to(\"admin\").emit(\"admin:update\", adminState);", + "replace": " lastAdminJson = adminJson;\n // mutant: changed admin state is not broadcast" + } + ] + }, + { + "id": "credit-checkout-ignores-wallet", + "desc": "A credit checkout pays entirely externally despite available credit.", + "scenario": "tracks/ecommerce/scenarios/progression-store-credit.json", + "targets": [ + "ecommerce.feature.store-credit.store-credit-750.750a" + ], + "file": "server/src/credit.ts", + "edits": [ + { + "find": " const creditMinor = Math.min(Number(account.rows[0].credit_minor), totalMinor);", + "replace": " const creditMinor = 0;" + } + ] + }, + { + "id": "credit-grant-replay-increments-balance", + "desc": "Replaying a grant applies its credit to the wallet again.", + "scenario": "tracks/ecommerce/scenarios/progression-store-credit.json", + "targets": [ + "ecommerce.spec.store-credit.production-752.752a" + ], + "file": "server/src/credit.ts", + "edits": [ + { + "find": " if (!existing.rows.length) {", + "replace": " if (existing.rows.length) await client.query('UPDATE account SET credit_minor=credit_minor+$1 WHERE id=$2', [amountMinor, accountId]);\n if (!existing.rows.length) {" + } + ] + }, + { + "id": "customer-can-grant-credit", + "desc": "Customer authentication is accepted without staff authorization.", + "scenario": "tracks/ecommerce/scenarios/progression-store-credit.json", + "targets": [ + "ecommerce.spec.store-credit.production-753.753a" + ], + "file": "server/src/credit.ts", + "edits": [ + { + "find": " app.post('/api/staff/credit', auth, staff, async (req, res) => {", + "replace": " app.post('/api/staff/credit', auth, async (req, res) => {" + } + ] + }, + { + "id": "split-refund-does-not-restore-credit", + "desc": "The refund is recorded but its original wallet credit is not restored.", + "scenario": "tracks/ecommerce/scenarios/progression-split-tender-refunds.json", + "targets": [ + "ecommerce.feature.split-tender-refunds.split-tender-refunds-751.751a" + ], + "file": "server/src/progression.ts", + "edits": [ + { + "find": " await refundCredit(client, order.rows[0]);", + "replace": " // mutant: omit wallet restoration" + } + ] + }, + { + "id": "split-refund-duplicates-credit", + "desc": "A refund credits the wallet twice while recording one refund.", + "scenario": "tracks/ecommerce/scenarios/progression-split-tender-refunds.json", + "targets": [ + "ecommerce.spec.split-tender-refunds.production-756.756a" + ], + "file": "server/src/credit.ts", + "edits": [ + { + "find": "[delta, order.account_id]);", + "replace": "[delta * 2, order.account_id]);" + } + ] + }, + { + "id": "subscription-skips-due-purchase", + "desc": "Due deliveries are recorded as skipped although stock is available.", + "scenario": "tracks/ecommerce/scenarios/progression-subscriptions.json", + "targets": [ + "ecommerce.feature.subscriptions.subscriptions-760.760a" + ], + "file": "server/src/subscriptions.ts", + "edits": [ + { + "find": " if (stock.rows.reduce((sum, row) => sum + row.quantity, 0) >= subscription.quantity) {", + "replace": " if (false && stock.rows.reduce((sum, row) => sum + row.quantity, 0) >= subscription.quantity) {" + } + ] + }, + { + "id": "subscription-allows-foreign-cancellation", + "desc": "A customer can cancel another customer subscription.", + "scenario": "tracks/ecommerce/scenarios/progression-subscriptions.json", + "targets": [ + "ecommerce.spec.subscriptions.production-762.762a" + ], + "file": "server/src/subscriptions.ts", + "edits": [ + { + "find": " if (!row || row.account_id !== req.account!.id) {", + "replace": " if (!row) {" + } + ] + }, + { + "id": "subscription-pause-is-not-recorded", + "desc": "Pause acknowledges the request but the subscription remains active.", + "scenario": "tracks/ecommerce/scenarios/progression-subscriptions.json", + "targets": [ + "ecommerce.spec.subscriptions.production-763.763a" + ], + "file": "server/src/subscriptions.ts", + "edits": [ + { + "find": "UPDATE purchase_subscription SET status='paused',paused_at=now() WHERE id=$1", + "replace": "UPDATE purchase_subscription SET status='active',paused_at=now() WHERE id=$1" + } + ] + }, + { + "id": "credit-checkout-retains-purchased-cart", + "scenario": "tracks/ecommerce/scenarios/progression-store-credit.json", + "targets": [ + "ecommerce.spec.store-credit.production-754.754a" + ], + "desc": "The purchased cart remains available instead of being consumed by checkout.", + "file": "server/src/progression.ts", + "edits": [ + { + "find": " await client.query(`DELETE FROM cart_item WHERE cart_id = $1`, [cart.rows[0].id]);", + "replace": " // Mutation: keep checked-out cart lines." + } + ] + }, + { + "id": "pending-subscriptions-are-cleared-at-startup", + "desc": "Restart erases pending subscription work while preserving ordinary timer execution.", + "file": "server/src/subscriptions.ts", + "scenario": "tracks/ecommerce/scenarios/progression-subscriptions.json", + "targets": [ + "ecommerce.spec.subscriptions.production-761.761a" + ], + "edits": [ + { + "find": " `);\n}\n\nexport function registerSubscriptions", + "replace": " `);\n await pool.query(\"UPDATE purchase_subscription SET status='cancelled' WHERE status='active'\");\n}\n\nexport function registerSubscriptions" + } + ] + }, + { + "id": "credit-balance-is-cleared-at-startup", + "desc": "Restart clears an issued wallet balance while leaving accounts present.", + "file": "server/src/credit.ts", + "scenario": "tracks/ecommerce/scenarios/progression-store-credit.json", + "targets": [ + "ecommerce.spec.store-credit.production-755.755a" + ], + "edits": [ + { + "find": " `);\n}\n\nexport async function spendCredit", + "replace": " `);\n await pool.query(\"UPDATE account SET credit_minor=0\");\n}\n\nexport async function spendCredit" + } + ] + }, + { + "id": "bundle-definition-loses-component-quantity", + "scenario": "tracks/ecommerce/scenarios/progression-product-bundles.json", + "targets": [ + "ecommerce.feature.product-bundles.product-bundles.740a" + ], + "desc": "definition loses component quantity", + "file": "server/src/bundles.ts", + "edits": [ + { + "find": "values.push({ ...component, itemId: item.rows[0].id });", + "replace": "values.push({ ...component, quantity: 1, itemId: item.rows[0].id });" + } + ] + }, + { + "id": "bundle-catalog-write-allows-customers", + "scenario": "tracks/ecommerce/scenarios/progression-product-bundles.json", + "targets": [ + "ecommerce.spec.bundle-integrity.bundle-743.743a" + ], + "desc": "catalog write allows customers", + "file": "server/src/bundles.ts", + "edits": [ + { + "find": "if (!actor?.is_admin && actor?.staff_role !== 'catalog')", + "replace": "if (false)" + } + ] + }, + { + "id": "bundle-checkout-price-not-snapshot", + "scenario": "tracks/ecommerce/scenarios/progression-bundle-checkout.json", + "targets": [ + "ecommerce.feature.bundle-checkout.bundle-checkout.741a" + ], + "desc": "checkout price not snapshot", + "file": "server/src/bundles.ts", + "edits": [ + { + "find": "[cart.rows[0].id, bundleId, bundle.price, JSON.stringify(allocations), JSON.stringify(bundle.bundle_components)]", + "replace": "[cart.rows[0].id, bundleId, bundle.price + 1, JSON.stringify(allocations), JSON.stringify(bundle.bundle_components)]" + } + ] + }, + { + "id": "bundle-expiry-does-not-release-components", + "scenario": "tracks/ecommerce/scenarios/progression-bundle-checkout.json", + "targets": [ + "ecommerce.spec.bundle-integrity.bundle-746.746a" + ], + "desc": "expiry does not release components", + "file": "server/src/progression.ts", + "edits": [ + { + "find": "await releaseBundle(client, bundle.rows[0].component_allocations);", + "replace": "/* mutant: component holds leak after expiration */" + } + ] + }, + { + "id": "bundle-return-loses-original-components", + "scenario": "tracks/ecommerce/scenarios/progression-bundle-returns.json", + "targets": [ + "ecommerce.feature.bundle-returns.bundle-returns.742a" + ], + "desc": "return loses original components", + "file": "server/src/bundles.ts", + "edits": [ + { + "find": "await releaseBundle(client, line.component_allocations);", + "replace": "/* mutant: purchased components are not restored */" + } + ] + }, + { + "id": "bundle-return-replay-restocks-again", + "scenario": "tracks/ecommerce/scenarios/progression-bundle-returns.json", + "targets": [ + "ecommerce.spec.bundle-integrity.bundle-742.742b" + ], + "desc": "return replay restocks again", + "file": "server/src/bundles.ts", + "edits": [ + { + "find": "WHERE order_id=$1 AND is_bundle AND NOT returned FOR UPDATE", + "replace": "WHERE order_id=$1 AND is_bundle FOR UPDATE" + } + ] + }, + { + "id": "bundle-return-crosses-account-boundary", + "scenario": "tracks/ecommerce/scenarios/progression-bundle-returns.json", + "targets": [ + "ecommerce.spec.bundle-integrity.bundle-748.748a" + ], + "desc": "return crosses account boundary", + "file": "server/src/bundles.ts", + "edits": [ + { + "find": "WHERE id=$1 AND account_id=$2 AND status IN ('shipped','delivered')", + "replace": "WHERE id=$1 AND $2::integer=$2::integer AND status IN ('shipped','delivered')" + } + ] + }, + { + "id": "bundle-components-can-overdraw", + "scenario": "tracks/ecommerce/scenarios/progression-bundle-checkout.json", + "targets": [ + "ecommerce.spec.bundle-integrity.bundle-744.744a", + "ecommerce.spec.bundle-integrity.bundle-745.745a" + ], + "desc": "components can overdraw", + "file": "server/src/bundles.ts", + "edits": [ + { + "find": "if (rows.rows.reduce((sum, row) => sum + row.quantity, 0) < component.quantity) throw new Error('A component is unavailable');", + "replace": "// mutant: incomplete component reservation is accepted" + } + ] + }, + { + "id": "bundle-checkout-reuses-reservation", + "scenario": "tracks/ecommerce/scenarios/progression-bundle-checkout.json", + "targets": [ + "ecommerce.spec.bundle-integrity.bundle-747.747a" + ], + "desc": "checkout reuses reservation", + "file": "server/src/progression.ts", + "edits": [ + { + "find": "await client.query(`DELETE FROM cart_item WHERE cart_id = $1`, [cart.rows[0].id]);", + "replace": "// mutant: cart survives checkout" + } + ] + }, + { + "id": "return-after-support-refund-is-blocked", + "scenario": "tracks/ecommerce/scenarios/progression-support-return-interaction.json", + "targets": [ + "ecommerce.feature.split-tender-refunds.return-refund-interaction.757a" + ], + "desc": "Reject a valid physical return after a financial refund.", + "file": "server/src/index.ts", + "edits": [ + { + "find": " if (lineRow.rows[0].returned) {", + "replace": " if (lineRow.rows[0].returned || Number(orderRow.rows[0].refund_total) > 0) {" + } + ] + }, + { + "id": "support-refund-after-return-pays-twice", + "scenario": "tracks/ecommerce/scenarios/progression-support-return-interaction.json", + "targets": [ + "ecommerce.feature.split-tender-refunds.return-refund-interaction.757b" + ], + "desc": "Pay the full order again after a physical return.", + "file": "server/src/progression.ts", + "edits": [ + { + "find": " await client.query(`UPDATE orders SET refund_total = total, status = CASE", + "replace": " await client.query(`UPDATE orders SET refund_total = refund_total + total, status = CASE" + } + ] + }, + { + "id": "progression-support-history-anonymous-leak", + "scenario": "tracks/ecommerce/scenarios/progression-support-history.json", + "targets": [ + "ecommerce.spec.access-control.support-history-logout.612d" + ], + "desc": "Return private support subjects to signed-out visitors while preserving authenticated ownership filtering.", + "file": "server/src/progression.ts", + "edits": [ + { + "find": " if (!account) return [];\n const where = account.isAdmin || account.isStaff ? \"TRUE\" : \"sc.account_id = $1\";\n const values = account.isAdmin || account.isStaff ? [] : [account.id];", + "replace": " const where = !account || account.isAdmin || account.isStaff ? \"TRUE\" : \"sc.account_id = $1\";\n const values = !account || account.isAdmin || account.isStaff ? [] : [account.id];" + } + ] + }, + { + "id": "checkout-crash-integrity", + "scenario": "tracks/ecommerce/scenarios/progression-checkout-crash.json", + "targets": [ + "ecommerce.spec.state-durability.checkout-crash-integrity.910a" + ], + "desc": "A lifecycle callback changes a prepared or cleared cart to quantity two, leaving neither a legal rollback nor a complete checkout.", + "file": "server/src/index.ts", + "edits": [ + { + "find": " await initializeProgressionSchema(pool);", + "replace": " await initializeProgressionSchema(pool);\n await pool.query(`INSERT INTO cart_item (cart_id, item_id, quantity) SELECT c.id, MIN(oi.item_id), 2 FROM cart c JOIN orders o ON o.account_id=c.account_id JOIN order_item oi ON oi.order_id=o.id GROUP BY c.id ON CONFLICT (cart_id,item_id) DO UPDATE SET quantity=2`);" + } + ] + }, + { + "id": "checkout-crash-durability", + "scenario": "tracks/ecommerce/scenarios/progression-checkout-crash.json", + "targets": [ + "ecommerce.spec.state-durability.checkout-crash-durability.910b" + ], + "desc": "A lifecycle callback corrupts earlier order totals. The unchanged prepared snapshots and acknowledged baseline must expose the damage.", + "file": "server/src/index.ts", + "edits": [ + { + "find": " await initializeProgressionSchema(pool);", + "replace": " await initializeProgressionSchema(pool);\n await pool.query('UPDATE orders SET total=0');" + } + ] + }, + { + "id": "review-script-unsafe-render", + "scenario": "tracks/ecommerce/scenarios/progression-review-script.json", + "targets": [ + "ecommerce.progression.review-access-specifications.stored-review-script.9180a" + ], + "desc": "Render stored review text as HTML so it executes in another customer session.", + "file": "client/src/App.tsx", + "edits": [ + { + "find": "
{r.comment}
", + "replace": "
" + } + ] + }, + { + "id": "review-script-reject-all", + "scenario": "tracks/ecommerce/scenarios/progression-review-script.json", + "targets": [ + "ecommerce.progression.review-access-specifications.stored-review-script.9180a" + ], + "desc": "Reject all nonempty reviews, including the required benign review; absence of script is insufficient.", + "file": "server/src/index.ts", + "edits": [ + { + "find": "const { rating, comment } = req.body ?? {};", + "replace": "const { rating, comment } = req.body ?? {};\n if (String(comment).length > 0) { res.status(400).json({ error: \"Review rejected\" }); return; }" + } + ] + }, + { + "id": "review-owner-trust-username", + "scenario": "tracks/ecommerce/scenarios/progression-review-access.json", + "targets": [ + "ecommerce.progression.review-access-specifications.review-eligibility-direct.618a" + ], + "desc": "Trust the submitted buyer username instead of the authenticated caller.", + "file": "server/src/index.ts", + "edits": [ + { + "find": "\"/api/items/:id/reviews\",\n requireAuth,\n asyncHandler(async (req, res) => {\n const itemId = Number(req.params.id);\n const accountId = req.account!.id;", + "replace": "\"/api/items/:id/reviews\",\n requireAuth,\n asyncHandler(async (req, res) => {\n const itemId = Number(req.params.id);\n const accountId = req.body?.username ? (await pool.query(\"SELECT id FROM account WHERE username = $1\", [req.body.username])).rows[0]?.id : req.account!.id;" + } + ] + }, + { + "id": "review-owner-deny-after-write", + "scenario": "tracks/ecommerce/scenarios/progression-review-access.json", + "targets": [ + "ecommerce.progression.review-access-specifications.review-eligibility-direct.618a" + ], + "desc": "Replace the buyer review under a forged username, then return a refusal.", + "file": "server/src/index.ts", + "edits": [ + { + "find": "\"/api/items/:id/reviews\",\n requireAuth,\n asyncHandler(async (req, res) => {\n const itemId = Number(req.params.id);\n const accountId = req.account!.id;", + "replace": "\"/api/items/:id/reviews\",\n requireAuth,\n asyncHandler(async (req, res) => {\n const itemId = Number(req.params.id);\n const accountId = req.body?.username ? (await pool.query(\"SELECT id FROM account WHERE username = $1\", [req.body.username])).rows[0]?.id : req.account!.id;" + }, + { + "find": "const { reviews, average } = await buildItemReviews(itemId);\n io.emit(\"review:update\", { itemId, reviews, average });", + "replace": "if (req.body?.username) { res.status(403).json({ error: \"Refused after write\" }); return; }\n const { reviews, average } = await buildItemReviews(itemId);\n io.emit(\"review:update\", { itemId, reviews, average });" + } + ] + }, + { + "id": "review-owner-reject-all", + "scenario": "tracks/ecommerce/scenarios/progression-review-access.json", + "targets": [ + "ecommerce.progression.review-access-specifications.review-eligibility-direct.618a" + ], + "desc": "Reject the legitimate buyer review as well as unauthorized reviews.", + "file": "server/src/index.ts", + "edits": [ + { + "find": "const { rating, comment } = req.body ?? {};", + "replace": "const { rating, comment } = req.body ?? {};\n if (String(comment).length > 0) { res.status(403).json({ error: \"Reject all reviews\" }); return; }" + } + ] + }, + { + "id": "password-verification-truncates-utf8", + "scenario": "tracks/ecommerce/scenarios/01-account-password.json", + "targets": [ + "ecommerce.feature.accounts.accounts.1c" + ], + "desc": "Hash and verify only the first 72 UTF-8 bytes, accepting a different password suffix.", + "file": "server/src/auth.ts", + "edits": [ + { + "find": "scrypt(password, salt, 64,", + "replace": "scrypt(Buffer.from(password).subarray(0, 72), salt, 64," + } + ] + }, + { + "id": "password-verification-rejects-every-login", + "scenario": "tracks/ecommerce/scenarios/01-account-password.json", + "targets": [ + "ecommerce.feature.accounts.accounts.1c" + ], + "desc": "Refuse even a correct password; refusal alone must not earn credit.", + "file": "server/src/auth.ts", + "edits": [ + { + "find": "return crypto.timingSafeEqual", + "replace": "return false && crypto.timingSafeEqual" + } + ] + } + ] +} diff --git a/tools/stack-bench/grader/mutations/spacetime-ecommerce.json b/tools/stack-bench/grader/mutations/spacetime-ecommerce.json new file mode 100644 index 00000000000..db58e3cccd5 --- /dev/null +++ b/tools/stack-bench/grader/mutations/spacetime-ecommerce.json @@ -0,0 +1,2734 @@ +{ + "schemaVersion": 3, + "fixtureSha256": "0126dfb2cb94547f985a2d73128914d59f3ed751727503076f34aa06455017e0", + "backend": "spacetime", + "track": "ecommerce", + "note": "Mutation definitions for the SpacetimeDB ecommerce reference.", + "mutations": [ + { + "id": "recommendation-dismissal-lost-on-reconnect", + "scenario": "tracks/ecommerce/scenarios/progression-recommendation-feedback.json", + "targets": [ + "ecommerce.spec.state-durability.recommendation-feedback-restart.504c" + ], + "desc": "Erase saved recommendation dismissals when a browser reconnects. This controls reconnect persistence, not backend restart alone.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": "// --- views ---", + "replace": "export const onConnect = spacetimedb.clientConnected((ctx) => { for (const row of ctx.db.recommendationDismissal.iter()) ctx.db.recommendationDismissal.id.delete(row.id); });\n// --- views ---" + } + ] + }, + { + "id": "pending-order-item-return-accepted", + "scenario": "tracks/ecommerce/scenarios/progression-order-return-boundary.json", + "targets": [ + "ecommerce.returns-pricing.cancellation-and-return.3f" + ], + "desc": "Accept a pending order return and restore its stock before shipment.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": "if (!['shipped', 'delivered'].includes(order.status)) throw new SenderError('Order has not shipped yet.');", + "replace": "if (!['pending', 'shipped', 'delivered'].includes(order.status)) throw new SenderError('Order has not shipped yet.');" + } + ] + }, + { + "id": "staff-admin-access-survives-role-removal", + "scenario": "tracks/ecommerce/scenarios/progression-staff-roles.json", + "targets": [ + "ecommerce.spec.access-control.staff-role-revocation.621d" + ], + "desc": "Keep administrator access after changing the assigned role back to staff.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": "ctx.db.account.id.update({ ...target, isAdmin: role === 'admin' });", + "replace": "ctx.db.account.id.update({ ...target, isAdmin: target.isAdmin || role === 'admin' });" + } + ] + }, + { + "id": "shipping-counts-sale-twice", + "scenario": "tracks/ecommerce/scenarios/progression-shipping-accounting.json", + "targets": [ + "ecommerce.inventory-operations.shipping-accounting.202e" + ], + "desc": "Shipping succeeds but doubles the completed sale value in authoritative revenue.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": " ctx.db.customerOrder.id.update({ ...order, status: 'shipped' });", + "replace": " ctx.db.customerOrder.id.update({ ...order, status: 'shipped', total: order.total * 2 });" + } + ] + }, + { + "id": "restock-client-snapshot-overwrites-concurrent-purchases", + "scenario": "tracks/ecommerce/scenarios/01-restock-race.json", + "targets": [ + "ecommerce.spec.concurrency-safety.restock-race.202a" + ], + "desc": "Compute absolute restock quantity when the administrator edits the form and store that captured value in the reducer. A fixed 500 ms submission delay widens the stale-write window. Serial purchases and restocks still work; intervening purchases can be overwritten. This is a stale-form lost update, not a race inside an atomic reducer.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": "ctx.db.stock.insert({ ...existing, quantity: existing.quantity + quantity });\n } else {\n ctx.db.stock.insert({ item_id: itemId, warehouse_id: warehouseId, quantity });\n }\n for (const alert of", + "replace": "ctx.db.stock.insert({ ...existing, quantity });\n } else {\n ctx.db.stock.insert({ item_id: itemId, warehouse_id: warehouseId, quantity });\n }\n for (const alert of" + }, + { + "file": "client/src/components/AdminPanel.tsx", + "find": "onChange={(e) => setRestockInputs((v) => ({ ...v, [k]: e.target.value }))}", + "replace": "onChange={(e) => setRestockInputs((v) => ({ ...v, [k]: String(stockOf(item.id, wh.id) + Number(e.target.value)) }))}" + }, + { + "file": "client/src/App.tsx", + "find": " await conn?.reducers.adminRestock({ itemId, warehouseId, quantity });", + "replace": " // Mutant: widen the stale form submission window without changing serial behavior.\n await new Promise(resolve => setTimeout(resolve, 500));\n await conn?.reducers.adminRestock({ itemId, warehouseId, quantity });" + } + ] + }, + { + "id": "signup-binds-the-new-account-to-the-admin-session", + "scenario": "tracks/ecommerce/scenarios/01-account-create.json", + "targets": [ + "ecommerce.feature.accounts.accounts.1a" + ], + "desc": "Create the requested account but bind the new browser session to the administrator, so account creation no longer signs the visitor in as the account it created.", + "file": "backend/spacetimedb/src/auth.ts", + "edits": [ + { + "find": " bindSession(tx, account.id);\n return true;\n });\n }\n);\n\nexport const signIn", + "replace": " bindSession(tx, tx.db.account.username.find('admin')!.id);\n return true;\n });\n }\n);\n\nexport const signIn" + } + ] + }, + { + "id": "duplicate-signup-is-silently-ignored", + "scenario": "tracks/ecommerce/scenarios/01-account-duplicate.json", + "targets": [ + "ecommerce.feature.accounts.accounts.1b" + ], + "desc": "Return success for a taken username without creating a session or surfacing the required refusal.", + "file": "backend/spacetimedb/src/auth.ts", + "edits": [ + { + "find": "if (tx.db.account.username.find(name) || tx.db.account.passwordSalt.find(passwordSalt)) return false;", + "replace": "if (tx.db.account.username.find(name) || tx.db.account.passwordSalt.find(passwordSalt)) return true;" + } + ] + }, + { + "id": "signin-does-not-verify-the-password", + "scenario": "tracks/ecommerce/scenarios/01-account-password.json", + "targets": [ + "ecommerce.feature.accounts.accounts.1c" + ], + "desc": "Accept a known username without comparing the supplied password hash.", + "file": "backend/spacetimedb/src/auth.ts", + "edits": [ + { + "find": "const valid = !!account && sameHash(digest, account.passwordHash);", + "replace": "const valid = !!account;" + } + ] + }, + { + "id": "signout-keeps-the-account-session", + "scenario": "tracks/ecommerce/scenarios/01-account-signout.json", + "targets": [ + "ecommerce.feature.accounts.accounts.1d" + ], + "desc": "Leave the current account session in place when the visitor signs out.", + "file": "client/src/components/AuthWidget.tsx", + "edits": [ + { + "find": " await connection.reducers.signOut({});\n clearToken(); location.reload();", + "replace": " location.reload(); // mutant: keep the account and credential" + } + ] + }, + { + "id": "session-token-is-not-persisted-for-reload", + "scenario": "tracks/ecommerce/scenarios/01-account-reload.json", + "targets": [ + "ecommerce.spec.state-durability.session-reload.1e" + ], + "desc": "Discard the connection token instead of persisting it, so a reload receives a new identity with no account session.", + "file": "client/src/main.tsx", + "edits": [ + { + "find": ".onConnect((_connection, _identity, token) => saveToken(token));", + "replace": ".onConnect((_connection, _identity, token) => { saveToken(token); sessionStorage.clear(); });" + } + ] + }, + { + "id": "catalog-seeds-the-wrong-air-purifier-price", + "scenario": "tracks/ecommerce/scenarios/01-catalog-values.json", + "targets": [ + "ecommerce.feature.catalog.catalog-values.2a" + ], + "desc": "Seed Air Purifier with an incorrect stored price while leaving the rest of the catalog intact.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": " ['Air Purifier', 189.0, 60, 40, 'Home'],", + "replace": " ['Air Purifier', 999.0, 60, 40, 'Home']," + } + ] + }, + { + "id": "catalog-tie-breaks-in-reverse-alphabetical-order--01-catalog-ranking", + "scenario": "tracks/ecommerce/scenarios/01-catalog-ranking.json", + "targets": [ + "ecommerce.feature.catalog.catalog-ranking.2b" + ], + "desc": "Reverse the specified alphabetical tie-breaker. This necessarily breaks both the initial sequence and the post-purchase sequence in the same scenario.", + "file": "client/src/App.tsx", + "edits": [ + { + "find": " return a.name.localeCompare(b.name);", + "replace": " return b.name.localeCompare(a.name);" + } + ] + }, + { + "id": "catalog-tie-breaks-in-reverse-alphabetical-order--01-core", + "scenario": "tracks/ecommerce/scenarios/01-core.json", + "targets": [ + "ecommerce.spec.live-state.ranking.2c" + ], + "desc": "Reverse the specified alphabetical tie-breaker. This necessarily breaks both the initial sequence and the post-purchase sequence in the same scenario.", + "file": "client/src/App.tsx", + "edits": [ + { + "find": " return a.name.localeCompare(b.name);", + "replace": " return b.name.localeCompare(a.name);" + } + ] + }, + { + "id": "purchase-does-not-update-ranking-count", + "scenario": "tracks/ecommerce/scenarios/01-core.json", + "targets": [ + "ecommerce.spec.live-state.ranking.2c" + ], + "desc": "Complete the purchase but leave its popularity count unchanged, so open storefronts cannot rank the purchased item first.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": " bumpPurchaseCount(ctx, itemId, quantity);", + "replace": " // mutant: buy-now never advances the ranking count" + } + ] + }, + { + "id": "signed-out-purchase-bypasses-account-check", + "scenario": "tracks/ecommerce/scenarios/progression-signed-out-purchase.json", + "targets": [ + "ecommerce.spec.access-control.signed-out-purchase.3a" + ], + "desc": "Expose the guest purchase button and accept its purchase as the existing administrator. The stock observation then exercises the broken account boundary; normal signed-in purchases remain unchanged.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": "export const buyNow = spacetimedb.reducer({ itemId: t.u64() }, (ctx, { itemId }) => {\n const acc = requireAccount(ctx);", + "replace": "export const buyNow = spacetimedb.reducer({ itemId: t.u64() }, (ctx, { itemId }) => {\n const acc = getAccountId(ctx) === null ? ctx.db.account.username.find('admin')! : requireAccount(ctx);" + }, + { + "file": "client/src/components/ItemCard.tsx", + "find": " {isSignedIn && (", + "replace": " {true && (" + } + ] + }, + { + "id": "buy-now-creates-orders-without-reserving-stock--01-buying", + "scenario": "tracks/ecommerce/scenarios/01-buying.json", + "targets": [ + "ecommerce.spec.live-state.purchase-stock.3b" + ], + "desc": "Create purchase orders without reserving inventory. The same defect necessarily breaks live purchase stock and the sell-out portion of the stock-limit check.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": " const allocations = decrementStockTracked(ctx, itemId, quantity);", + "replace": " const allocations: Array<{ warehouseId: bigint; quantity: number }> = [];" + } + ] + }, + { + "id": "buy-now-creates-orders-without-reserving-stock--stock-limit", + "scenario": "tracks/ecommerce/scenarios/progression-stock-limit.json", + "targets": [ + "ecommerce.spec.concurrency-safety.stock-limit.3d" + ], + "desc": "Create purchase orders without reserving inventory. The same defect necessarily breaks live purchase stock and the sell-out portion of the stock-limit check.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": " const allocations = decrementStockTracked(ctx, itemId, quantity);", + "replace": " const allocations: Array<{ warehouseId: bigint; quantity: number }> = [];" + } + ] + }, + { + "id": "restock-race-records-wrong-order-total", + "scenario": "tracks/ecommerce/scenarios/01-restock-race.json", + "targets": [ + "ecommerce.spec.concurrency-safety.restock-race.202a" + ], + "desc": "Purchases preserve stock and visible order counts but record the wrong booked total. Native mixed-race reconciliation must reject them.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": " total: Math.round(price * 100) * quantity / 100,\n status: 'pending',", + "replace": " total: Math.round(price * 100) * quantity / 100 + 1,\n status: 'pending'," + } + ] + }, + { + "id": "buy-now-records-the-wrong-order-total", + "scenario": "tracks/ecommerce/scenarios/progression-purchasing.json", + "targets": [ + "ecommerce.feature.purchasing.purchase-order.3c" + ], + "desc": "Record a completed buy-now order one dollar above the stored item price.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": " total: Math.round(price * 100) * quantity / 100,\n status: 'pending',", + "replace": " total: Math.round(price * 100) * quantity / 100 + 1,\n status: 'pending'," + } + ] + }, + { + "id": "existing-cart-line-does-not-increment-basic-cart", + "scenario": "tracks/ecommerce/scenarios/progression-cart-checkout.json", + "targets": [ + "ecommerce.feature.cart-checkout.cart.4a" + ], + "desc": "Write an existing cart line back without incrementing its quantity.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": "ctx.db.cartItem.id.update({ ...existing, quantity: existing.quantity + 1 });", + "replace": "ctx.db.cartItem.id.update({ ...existing, quantity: existing.quantity });" + } + ] + }, + { + "id": "cart-is-deleted-when-owner-disconnects", + "scenario": "tracks/ecommerce/scenarios/01-cart.json", + "targets": [ + "ecommerce.spec.state-durability.cart-reload.4b" + ], + "desc": "Delete the account cart on transport disconnect. Reload loses stored cart contents even after the same account signs in again; account and session records remain intact.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": "// --- views ---", + "replace": "export const onDisconnect = spacetimedb.clientDisconnected((ctx) => {\n const accountId = getAccountId(ctx);\n if (accountId !== null) for (const row of [...ctx.db.cartItem.byAccountItem.filter(accountId)]) ctx.db.cartItem.id.delete(row.id);\n});\n// --- views ---" + } + ] + }, + { + "id": "signin-binds-the-second-client-to-a-different-account", + "scenario": "tracks/ecommerce/scenarios/01-cart.json", + "targets": [ + "ecommerce.spec.live-state.shared-cart.4c" + ], + "desc": "Authenticate valid credentials but bind the second connection to the administrator account, so two sessions for one customer do not share the customer's cart.", + "file": "backend/spacetimedb/src/auth.ts", + "edits": [ + { + "find": " if (!current || current.passwordHash !== account.passwordHash) return false;\n bindSession(tx, account.id);", + "replace": " if (!current || current.passwordHash !== account.passwordHash) return false;\n bindSession(tx, tx.db.account.username.find('admin')!.id);" + } + ] + }, + { + "id": "checkout-does-not-empty-the-basic-cart", + "scenario": "tracks/ecommerce/scenarios/progression-cart-checkout.json", + "targets": [ + "ecommerce.feature.cart-checkout.cart.4d" + ], + "desc": "Leave completed checkout lines in the durable cart.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": " for (const line of lines) ctx.db.cartItem.id.delete(line.id);", + "replace": " // mutant: checked-out cart lines remain" + } + ] + }, + { + "id": "new-review-is-accepted-without-being-stored", + "scenario": "tracks/ecommerce/scenarios/01-review-visibility.json", + "targets": [ + "ecommerce.feature.reviews.reviews.6a" + ], + "desc": "Accept an eligible new review but omit its durable insert, so neither author nor visitor can see it.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": " ctx.db.review.insert({\n id: 0n,\n itemId,\n accountId: acc.id,\n rating,\n comment,\n createdAt: ctx.timestamp,\n });", + "replace": " // mutant: accepted review is not persisted" + } + ] + }, + { + "id": "repeat-review-inserts-a-second-row", + "scenario": "tracks/ecommerce/scenarios/01-review-uniqueness.json", + "targets": [ + "ecommerce.spec.transactional-integrity.unique-review.6b" + ], + "desc": "Insert a second review row instead of updating the customer's existing item review.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": " ctx.db.review.id.update({ ...existing, rating, comment, createdAt: ctx.timestamp });", + "replace": " ctx.db.review.insert({ id: 0n, itemId, accountId: acc.id, rating, comment, createdAt: ctx.timestamp });" + } + ] + }, + { + "id": "review-average-counts-rows-instead-of-ratings", + "scenario": "tracks/ecommerce/scenarios/01-review-rating-live.json", + "targets": [ + "ecommerce.spec.live-state.rating.6c" + ], + "desc": "Compute the live average from a constant per row rather than each stored rating.", + "file": "client/src/components/ItemDetail.tsx", + "edits": [ + { + "find": " : reviews.reduce((sum, r) => sum + r.rating, 0) / reviews.length;", + "replace": " : reviews.reduce((sum) => sum + 1, 0) / reviews.length;" + } + ] + }, + { + "id": "every-signed-in-customer-is-treated-as-an-admin", + "scenario": "tracks/ecommerce/scenarios/01-warehouse-admin-staff.json", + "targets": [ + "ecommerce.spec.access-control.warehouse-area-boundary.7a" + ], + "desc": "Use account presence instead of the server-provided administrator flag to expose the admin area.", + "file": "client/src/App.tsx", + "edits": [ + { + "find": " const isAdmin = currentUser?.isAdmin ?? false;", + "replace": " const isAdmin = isSignedIn;" + } + ] + }, + { + "id": "warehouse-view-omits-west", + "scenario": "tracks/ecommerce/scenarios/01-warehouse-admin-staff.json", + "targets": [ + "ecommerce.feature.warehouse-admin.warehouse-view.7b" + ], + "desc": "Filter one real warehouse out of the administrator's inventory view.", + "file": "client/src/App.tsx", + "edits": [ + { + "find": " warehouses={warehouses}", + "replace": " warehouses={warehouses.filter((warehouse) => warehouse.name !== 'West')}" + } + ] + }, + { + "id": "guest-purchase-falls-back-to-the-admin-account", + "scenario": "tracks/ecommerce/scenarios/01-purchase-session.json", + "targets": [ + "ecommerce.spec.access-control.purchase-session.101a" + ], + "desc": "Allow an unauthenticated direct purchase by attributing missing sessions to the administrator account, while preserving the authorized control path.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": "export const buyNow = spacetimedb.reducer({ itemId: t.u64() }, (ctx, { itemId }) => {\n const acc = requireAccount(ctx);", + "replace": "export const buyNow = spacetimedb.reducer({ itemId: t.u64() }, (ctx, { itemId }) => {\n const accountId = getAccountId(ctx);\n const acc = (accountId === null ? null : ctx.db.account.id.find(accountId))\n ?? ctx.db.account.username.find('admin')!;" + } + ] + }, + { + "id": "direct-purchases-are-attributed-to-the-system-account", + "scenario": "tracks/ecommerce/scenarios/01-purchase-attribution.json", + "targets": [ + "ecommerce.spec.access-control.purchase-attribution.102a" + ], + "desc": "Store every buy-now order under the administrator instead of the authenticated caller.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": " accountId,\n createdAt: ctx.timestamp,\n total: Math.round(price * 100) * quantity / 100,", + "replace": " accountId: ctx.db.account.username.find('admin')!.id,\n createdAt: ctx.timestamp,\n total: Math.round(price * 100) * quantity / 100," + } + ] + }, + { + "id": "direct-restock-does-not-require-an-admin", + "scenario": "tracks/ecommerce/scenarios/01-admin-write-staff.json", + "targets": [ + "ecommerce.spec.access-control.warehouse-write-boundary.103b" + ], + "desc": "Remove the server-side administrator check from the restock reducer.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": "export const adminRestock = spacetimedb.reducer(\n { itemId: t.u64(), warehouseId: t.u64(), quantity: t.u32() },\n (ctx, { itemId, warehouseId, quantity }) => {\n requireAdmin(ctx);", + "replace": "export const adminRestock = spacetimedb.reducer(\n { itemId: t.u64(), warehouseId: t.u64(), quantity: t.u32() },\n (ctx, { itemId, warehouseId, quantity }) => {\n // mutant: no administrator check" + } + ] + }, + { + "id": "direct-purchase-ignores-the-stored-price", + "scenario": "tracks/ecommerce/scenarios/01-server-price.json", + "targets": [ + "ecommerce.spec.transactional-integrity.server-price.104a" + ], + "desc": "Create the direct purchase order one dollar above the authoritative stored price.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": " total: Math.round(price * 100) * quantity / 100,\n status: 'pending',", + "replace": " total: 1,\n status: 'pending'," + } + ] + }, + { + "id": "account-state-token-is-not-restored-after-reload", + "scenario": "tracks/ecommerce/scenarios/progression-account-state-reload.json", + "targets": [ + "ecommerce.spec.state-durability.account-state-recovery.105a" + ], + "desc": "Discard the saved token after connection, preserving signup but losing access to the account, cart and orders on the next reload.", + "file": "client/src/main.tsx", + "edits": [ + { + "find": ".onConnect((_connection, _identity, token) => saveToken(token));", + "replace": ".onConnect((_connection, _identity, token) => { saveToken(token); sessionStorage.clear(); });" + } + ] + }, + { + "id": "reconnect-discards-the-visible-account-state", + "scenario": "tracks/ecommerce/scenarios/progression-account-state-reconnect.json", + "targets": [ + "ecommerce.spec.state-durability.account-state-recovery.105b" + ], + "desc": "Keep normal reload recovery but discard the client account projection when the browser comes back online.", + "file": "client/src/App.tsx", + "edits": [ + { + "find": " const currentUser = currentUserRows[0] ?? null;", + "replace": " const [discardAccountAfterReconnect, setDiscardAccountAfterReconnect] = useState(false);\n useEffect(() => {\n const discardAccount = () => setDiscardAccountAfterReconnect(true);\n window.addEventListener('online', discardAccount);\n return () => window.removeEventListener('online', discardAccount);\n }, []);\n const currentUser = discardAccountAfterReconnect ? null : currentUserRows[0] ?? null;" + } + ] + }, + { + "id": "order-views-return-every-customers-orders", + "scenario": "tracks/ecommerce/scenarios/01-order-ownership.json", + "targets": [ + "ecommerce.spec.access-control.order-ownership.106a" + ], + "desc": "Remove account filters from both order views, exposing another customer's order and its line items.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": " const rows = [...ctx.db.customerOrder.accountId.filter(accountId)];", + "replace": " const rows = [...ctx.db.customerOrder.iter()];" + }, + { + "find": " for (const o of ctx.db.customerOrder.accountId.filter(accountId)) {", + "replace": " for (const o of ctx.db.customerOrder.iter()) {" + } + ] + }, + { + "id": "admin-revenue-double-counts-every-order", + "scenario": "tracks/ecommerce/scenarios/progression-books-balance.json", + "targets": [ + "ecommerce.spec.transactional-integrity.books-balance.107a" + ], + "desc": "Count every completed order twice in the administrator revenue projection.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": " total += o.total - o.refundedTotal;", + "replace": " total += (o.total - o.refundedTotal) * 2;" + } + ] + }, + { + "id": "purchases-do-not-leave-the-warehouses", + "scenario": "tracks/ecommerce/scenarios/progression-books-balance.json", + "targets": [ + "ecommerce.spec.transactional-integrity.books-balance.107b" + ], + "desc": "Create normal orders and revenue while leaving warehouse stock unchanged.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": " const allocations = decrementStockTracked(ctx, itemId, quantity);", + "replace": " const allocations: Array<{ warehouseId: bigint; quantity: number }> = [];" + } + ] + }, + { + "id": "review-purchase-eligibility-is-not-checked", + "scenario": "tracks/ecommerce/scenarios/01-review-eligibility.json", + "targets": [ + "ecommerce.spec.access-control.review-eligibility.108a" + ], + "desc": "Allow a signed-in customer to review an item with no matching purchase.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": " if (!bought) throw new SenderError('You can only review items you have purchased.');", + "replace": " // mutant: purchase eligibility is not checked" + } + ] + }, + { + "id": "eligible-review-is-accepted-without-being-stored", + "scenario": "tracks/ecommerce/scenarios/01-review-eligibility.json", + "targets": [ + "ecommerce.spec.access-control.review-eligibility.108b", + "ecommerce.spec.access-control.review-eligibility.108a" + ], + "desc": "Keep the non-buyer refusal but omit the insert for a buyer's eligible new review. Both eligibility criteria require a successfully stored eligible review as a positive control; this does not establish a non-buyer authorization defect.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": " ctx.db.review.insert({\n id: 0n,\n itemId,\n accountId: acc.id,\n rating,\n comment,\n createdAt: ctx.timestamp,\n });", + "replace": " // mutant: eligible review is acknowledged but not persisted" + } + ] + }, + { + "id": "cart-line-lookup-ignores-cart-ownership", + "scenario": "tracks/ecommerce/scenarios/01-cart-boundary.json", + "targets": [ + "ecommerce.spec.access-control.cart-boundary.109a" + ], + "desc": "Find an existing cart line by item alone, so the same named add action from another customer increments the owner's line instead of that customer's cart.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": "function findCartLine(ctx: Ctx, accountId: bigint, itemId: bigint) {\n for (const row of ctx.db.cartItem.byAccountItem.filter([accountId, itemId])) {\n return row;\n }\n return null;\n}", + "replace": "function findCartLine(ctx: Ctx, _accountId: bigint, itemId: bigint) {\n for (const row of ctx.db.cartItem.iter()) {\n if (row.itemId === itemId) return row;\n }\n return null;\n}" + } + ] + }, + { + "id": "purchase-does-not-reserve-stock-last-unit", + "scenario": "tracks/ecommerce/scenarios/01-last-unit.json", + "targets": [ + "ecommerce.spec.concurrency-safety.last-unit.201a", + "ecommerce.spec.concurrency-safety.last-unit.201b", + "ecommerce.spec.concurrency-safety.last-unit.201c" + ], + "desc": "Create purchase orders without reserving stock, proving the focused last-unit stock, order-count, and revenue consequences.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": " const allocations = decrementStockTracked(ctx, itemId, quantity);", + "replace": " const allocations: Array<{ warehouseId: bigint; quantity: number }> = [];" + } + ] + }, + { + "id": "existing-cart-line-does-not-increment", + "scenario": "tracks/ecommerce/scenarios/01-duplicate-checkout.json", + "targets": [ + "ecommerce.spec.concurrency-safety.duplicate-checkout.203a" + ], + "desc": "Render the old cart quantity after concurrent adds.", + "file": "client/src/components/CartPanel.tsx", + "edits": [ + { + "find": " value={line.quantity}", + "replace": " value={1}" + } + ] + }, + { + "id": "checkout-does-not-empty-cart", + "scenario": "tracks/ecommerce/scenarios/01-duplicate-checkout.json", + "targets": [ + "ecommerce.spec.concurrency-safety.duplicate-checkout.203b" + ], + "desc": "Keep checked-out cart lines so the next serialized checkout creates a duplicate order.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": " for (const line of lines) ctx.db.cartItem.id.delete(line.id);", + "replace": " // mutant: checked-out lines remain in the cart" + } + ] + }, + { + "id": "stock-subscription-snapshotted-once", + "scenario": "tracks/ecommerce/scenarios/01-external-live-sync.json", + "targets": [ + "ecommerce.spec.external-data-sync.external-stock.901a" + ], + "desc": "Render the first non-empty stock snapshot forever instead of following committed subscription updates.", + "file": "client/src/App.tsx", + "edits": [ + { + "find": "import { useEffect, useMemo, useState } from 'react';", + "replace": "import { useEffect, useMemo, useRef, useState } from 'react';" + }, + { + "find": " const [stocks] = useTable(tables.stock);", + "replace": " const [liveStocks] = useTable(tables.stock);\n const initialStocks = useRef(null);\n if (initialStocks.current === null && liveStocks.length > 0) {\n initialStocks.current = liveStocks;\n }\n const stocks = initialStocks.current ?? liveStocks;" + } + ] + }, + { + "id": "stock-view-ignores-update-across-app-server-stop", + "scenario": "tracks/ecommerce/scenarios/01-external-server-restart-sync.json", + "targets": [ + "ecommerce.spec.external-data-sync.external-stock.901c" + ], + "desc": "Persist the first stock quantities in browser session storage and keep rendering them after app-server restart, including any frontend reload. Initial stock remains correct. This validates the stale-view oracle, not SpacetimeDB storage durability.", + "file": "client/src/App.tsx", + "edits": [ + { + "find": " const [stocks] = useTable(tables.stock);", + "replace": " const [liveStocks] = useTable(tables.stock);\n const cacheKey = 'stale-stock-quantities';\n let savedQuantities = sessionStorage.getItem(cacheKey);\n if (!savedQuantities && liveStocks.length > 0) {\n savedQuantities = JSON.stringify(Object.fromEntries(liveStocks.map(row => [`${row.itemId}-${row.warehouseId}`, row.quantity])));\n sessionStorage.setItem(cacheKey, savedQuantities);\n }\n const quantities: Record = JSON.parse(savedQuantities ?? '{}');\n const stocks = liveStocks.map(row => ({ ...row, quantity: quantities[`${row.itemId}-${row.warehouseId}`] ?? row.quantity }));" + } + ] + }, + { + "id": "stock-view-keeps-pre-reconnect-snapshot", + "scenario": "tracks/ecommerce/scenarios/01-external-reconnect-sync.json", + "targets": [ + "ecommerce.spec.external-data-sync.external-stock.901d" + ], + "desc": "Continue following stock until the browser goes offline, then retain the last online snapshot after network restoration.", + "file": "client/src/App.tsx", + "edits": [ + { + "find": "import { useEffect, useMemo, useState } from 'react';", + "replace": "import { useEffect, useMemo, useRef, useState } from 'react';" + }, + { + "find": " const [stocks] = useTable(tables.stock);", + "replace": " const [liveStocks] = useTable(tables.stock);\n const [freezeStockAfterOffline, setFreezeStockAfterOffline] = useState(false);\n const lastOnlineStocks = useRef(liveStocks);\n useEffect(() => {\n const freezeStock = () => setFreezeStockAfterOffline(true);\n window.addEventListener('offline', freezeStock);\n return () => window.removeEventListener('offline', freezeStock);\n }, []);\n if (!freezeStockAfterOffline) {\n lastOnlineStocks.current = liveStocks;\n }\n const stocks = freezeStockAfterOffline ? lastOnlineStocks.current : liveStocks;" + } + ] + }, + { + "id": "open-review-list-snapshots-on-selection", + "scenario": "tracks/ecommerce/scenarios/progression-open-list-live.json", + "targets": [ + "ecommerce.spec.live-state.open-list.902a" + ], + "desc": "Snapshot the selected item's reviews when the detail opens instead of following later subscription updates.", + "file": "client/src/App.tsx", + "edits": [ + { + "find": "import { useEffect, useMemo, useState } from 'react';", + "replace": "import { useEffect, useMemo, useRef, useState } from 'react';" + }, + { + "find": " const selectedItemReviews = selectedItemId !== null ? reviewsByItem.get(selectedItemId) ?? [] : [];", + "replace": " const openedReviewItem = useRef(null);\n const openedReviews = useRef<(typeof reviews)[number][]>([]);\n if (selectedItemId !== openedReviewItem.current) {\n openedReviewItem.current = selectedItemId;\n openedReviews.current = selectedItemId !== null ? reviewsByItem.get(selectedItemId) ?? [] : [];\n }\n const selectedItemReviews = openedReviews.current;" + } + ] + }, + { + "id": "open-review-list-renders-each-review-twice", + "scenario": "tracks/ecommerce/scenarios/progression-open-list-live.json", + "targets": [ + "ecommerce.spec.live-state.open-list.902a" + ], + "desc": "Render every committed review twice in the already-open list.", + "file": "client/src/components/ItemDetail.tsx", + "edits": [ + { + "find": " {reviews.map((r) => (", + "replace": " {[...reviews, ...reviews].map((r) => (" + } + ] + }, + { + "id": "cancel-does-not-restore-stock-feature", + "scenario": "tracks/ecommerce/scenarios/02-order-cancellation-core.json", + "targets": [ + "ecommerce.returns-pricing.cancellation-and-return.3a" + ], + "desc": "The serialized cancellation reducer changes order state and purchase counts but skips allocation restoration.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": " restoreOrderItemStock(ctx, li);\n decrementPurchaseCount(ctx, li.itemId, li.quantity);", + "replace": " // mutant: cancellation does not restore its reserved stock\n decrementPurchaseCount(ctx, li.itemId, li.quantity);" + } + ] + }, + { + "id": "cancellation-accounting-loses-stock-restoration", + "scenario": "tracks/ecommerce/scenarios/02-invariants.json", + "targets": [ + "ecommerce.returns-pricing.refund-accounting.203a" + ], + "desc": "Cancellation removes revenue and changes order status, but loses the original warehouse stock restoration. The native refund-accounting assertion must detect this.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": " restoreOrderItemStock(ctx, li);\n decrementPurchaseCount(ctx, li.itemId, li.quantity);", + "replace": " // mutant: cancellation does not restore its reserved stock\n decrementPurchaseCount(ctx, li.itemId, li.quantity);" + } + ] + }, + { + "id": "cancel-does-not-restore-stock-fresh-client", + "scenario": "tracks/ecommerce/scenarios/02-self-contained.json", + "targets": [ + "ecommerce.inventory-operations.stock-conservation.202b", + "ecommerce.inventory-operations.stock-conservation.202c" + ], + "desc": "The serialized cancellation reducer skips allocation restoration, so a fresh client reads the persisted shortfall.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": " restoreOrderItemStock(ctx, li);\n decrementPurchaseCount(ctx, li.itemId, li.quantity);", + "replace": " // mutant: cancellation does not restore its reserved stock\n decrementPurchaseCount(ctx, li.itemId, li.quantity);" + } + ] + }, + { + "id": "cancel-restores-stock-but-keeps-pending-status", + "scenario": "tracks/ecommerce/scenarios/02-order-cancellation-history.json", + "targets": [ + "ecommerce.returns-pricing.cancellation-and-return.3b" + ], + "desc": "The serialized cancellation reducer restores allocations but writes pending back to order history.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": " ctx.db.customerOrder.id.update({ ...order, status: 'cancelled' });", + "replace": " ctx.db.customerOrder.id.update({ ...order, status: 'pending' });" + } + ] + }, + { + "id": "cancelled-order-remains-in-revenue-feature", + "scenario": "tracks/ecommerce/scenarios/02-order-cancellation-core.json", + "targets": [ + "ecommerce.returns-pricing.cancellation-and-return.3a" + ], + "desc": "The admin revenue view includes cancelled orders even though cancellation otherwise succeeds.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": " if (!isOrderCounted(o)) continue;\n total += o.total - o.refundedTotal;", + "replace": " total += o.total - o.refundedTotal;" + } + ] + }, + { + "id": "cancelled-order-remains-in-revenue-invariant", + "scenario": "tracks/ecommerce/scenarios/02-invariants.json", + "targets": [ + "ecommerce.returns-pricing.refund-accounting.203a" + ], + "desc": "The admin revenue view includes cancelled orders even though cancellation otherwise succeeds.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": " if (!isOrderCounted(o)) continue;\n total += o.total - o.refundedTotal;", + "replace": " total += o.total - o.refundedTotal;" + } + ] + }, + { + "id": "operator-authorization-allows-customer-transfer", + "scenario": "tracks/ecommerce/scenarios/02-strengthened.json", + "targets": [ + "ecommerce.operations-access.operator-authorization.201a" + ], + "desc": "The transfer reducer drops its administrator role gate.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": " (ctx, { itemId, fromWarehouseId, toWarehouseId, quantity }) => {\n requireAdmin(ctx);", + "replace": " (ctx, { itemId, fromWarehouseId, toWarehouseId, quantity }) => {\n // mutant: no administrator role check" + } + ] + }, + { + "id": "customer-can-ship-order-direct-1-1", + "scenario": "tracks/ecommerce/scenarios/02-server-actions.json", + "targets": [ + "ecommerce.operations-access.operator-authorization.201c" + ], + "desc": "The shipping reducer drops its staff role check while retaining pending-state validation.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": "export const shipOrder = spacetimedb.reducer({ orderId: t.u64() }, (ctx, { orderId }) => {\n requireStaffOrAdmin(ctx);", + "replace": "export const shipOrder = spacetimedb.reducer({ orderId: t.u64() }, (ctx, { orderId }) => {\n // mutant: no staff role check" + } + ] + }, + { + "id": "customer-can-cancel-foreign-order-1-1", + "scenario": "tracks/ecommerce/scenarios/02-server-actions.json", + "targets": [ + "ecommerce.operations-access.order-owner.204a" + ], + "desc": "Cancellation bypasses the owner helper while retaining missing-order and pending-state validation.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": "export const cancelOrder = spacetimedb.reducer({ orderId: t.u64() }, (ctx, { orderId }) => {\n const order = requireOrderOwner(ctx, orderId);", + "replace": "export const cancelOrder = spacetimedb.reducer({ orderId: t.u64() }, (ctx, { orderId }) => {\n const order = ctx.db.customerOrder.id.find(orderId);\n if (!order) throw new SenderError('Order not found.');" + } + ] + }, + { + "id": "queue-depth-lags-one-order", + "scenario": "tracks/ecommerce/scenarios/02-fulfilment-live.json", + "targets": [ + "ecommerce.operations-access.fulfilment-queue.1a" + ], + "desc": "The reactive queue renders every order but its visible depth remains one behind.", + "file": "client/src/components/FulfilmentPanel.tsx", + "edits": [ + { + "find": "Waiting: {queue.length}", + "replace": "Waiting: {Math.max(0, queue.length - 1)}" + } + ] + }, + { + "id": "ship-acknowledges-without-changing-status", + "scenario": "tracks/ecommerce/scenarios/02-fulfilment-ship.json", + "targets": [ + "ecommerce.operations-access.fulfilment-queue.1c" + ], + "desc": "The serialized shipping reducer accepts the call but writes pending back to the order.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": " ctx.db.customerOrder.id.update({ ...order, status: 'shipped' });", + "replace": " ctx.db.customerOrder.id.update({ ...order, status: 'pending' });" + } + ] + }, + { + "id": "customer-sees-fulfilment-navigation", + "scenario": "tracks/ecommerce/scenarios/02-features.json", + "targets": [ + "ecommerce.operations-access.fulfilment-queue.1d" + ], + "desc": "Expose the protected staff area to signed-in customers, including its navigation and content.", + "file": "client/src/App.tsx", + "edits": [ + { + "find": " const isStaff = currentUser?.isStaff ?? false;", + "replace": " const isStaff = isSignedIn;" + } + ] + }, + { + "id": "progression-customer-sees-fulfilment-content", + "scenario": "tracks/ecommerce/scenarios/02-fulfilment-access.json", + "targets": [ + "ecommerce.spec.access-control.fulfilment-area-boundary.1d" + ], + "desc": "Expose the protected staff area to signed-in customers, including its navigation and content.", + "file": "client/src/App.tsx", + "edits": [ + { + "find": " const isStaff = currentUser?.isStaff ?? false;", + "replace": " const isStaff = isSignedIn;" + } + ] + }, + { + "id": "operator-authorization-allows-customer-shipping", + "scenario": "tracks/ecommerce/scenarios/02-server-actions.json", + "targets": [ + "ecommerce.operations-access.operator-authorization.201c" + ], + "desc": "The shipping reducer drops the staff role check while retaining the pending-order guard.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": "export const shipOrder = spacetimedb.reducer({ orderId: t.u64() }, (ctx, { orderId }) => {\n requireStaffOrAdmin(ctx);", + "replace": "export const shipOrder = spacetimedb.reducer({ orderId: t.u64() }, (ctx, { orderId }) => {\n // mutant: no staff role check" + } + ] + }, + { + "id": "transfer-debits-source-without-crediting-existing-destination", + "scenario": "tracks/ecommerce/scenarios/02-strengthened.json", + "targets": [ + "ecommerce.inventory-operations.stock-conservation.202a", + "ecommerce.inventory-operations.warehouse-transfer.2a", + "ecommerce.operations-access.operator-authorization.201a" + ], + "desc": "A transfer debits the source row but writes the existing destination quantity back unchanged, violating both directional movement and total conservation inside the serialized reducer. It also breaks 201a's authorized-transfer positive control; that coupled failure is not independent evidence of an authorization defect.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": " ctx.db.stock.insert({ ...toRow, quantity: toRow.quantity + quantity });", + "replace": " ctx.db.stock.insert({ ...toRow, quantity: toRow.quantity });" + } + ] + }, + { + "id": "transfer-warehouse-totals-omit-destination-credit", + "scenario": "tracks/ecommerce/scenarios/02-transfer-totals.json", + "targets": [ + "ecommerce.inventory-operations.warehouse-transfer.2b" + ], + "desc": "The serialized transfer debits the source but writes the existing destination quantity back unchanged.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": " ctx.db.stock.insert({ ...toRow, quantity: toRow.quantity + quantity });", + "replace": " ctx.db.stock.insert({ ...toRow, quantity: toRow.quantity });" + } + ] + }, + { + "id": "transfer-overdraft-guard-removed", + "scenario": "tracks/ecommerce/scenarios/02-transfer-overdraw.json", + "targets": [ + "ecommerce.inventory-operations.warehouse-transfer.2c" + ], + "desc": "The serialized reducer no longer rejects insufficient source stock and commits negative source quantity.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": " if (available < quantity) {\n throw new SenderError(`Not enough stock in source warehouse: only ${available} available.`);\n }", + "replace": " // mutant: insufficient source stock is not rejected" + } + ] + }, + { + "id": "low-stock-excludes-boundary-ten", + "scenario": "tracks/ecommerce/scenarios/02-low-stock.json", + "targets": [ + "ecommerce.inventory-operations.operational-views.5a" + ], + "desc": "The reactive low-stock view uses a strict boundary and omits items with exactly ten units.", + "file": "client/src/App.tsx", + "edits": [ + { + "find": " .filter((i) => (stockByItem.get(i.id) ?? 0) <= LOW_STOCK_THRESHOLD)", + "replace": " .filter((i) => (stockByItem.get(i.id) ?? 0) < LOW_STOCK_THRESHOLD)" + } + ] + }, + { + "id": "category-totals-ignore-pending-purchases", + "scenario": "tracks/ecommerce/scenarios/02-operational-category-totals.json", + "targets": [ + "ecommerce.inventory-operations.operational-views.5b" + ], + "desc": "The category totals view includes only shipped orders, so a newly accepted pending purchase is absent.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": " for (const order of ctx.db.customerOrder.iter()) {\n if (!isOrderCounted(order)) continue;", + "replace": " for (const order of ctx.db.customerOrder.iter()) {\n if (order.status !== 'shipped') continue;" + } + ] + }, + { + "id": "recommendations-ignore-pending-purchases", + "scenario": "tracks/ecommerce/scenarios/02-operational-recommendations.json", + "targets": [ + "ecommerce.inventory-operations.operational-views.5c" + ], + "desc": "The personal recommendation view derives categories only from shipped orders, so a new pending purchase has no influence.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": " for (const order of ctx.db.customerOrder.accountId.filter(accountId)) {\n if (!isOrderCounted(order)) continue;", + "replace": " for (const order of ctx.db.customerOrder.accountId.filter(accountId)) {\n if (order.status !== 'shipped') continue;" + } + ] + }, + { + "id": "purchases-do-not-affect-best-sellers", + "scenario": "tracks/ecommerce/scenarios/02-operational-best-sellers.json", + "targets": [ + "ecommerce.inventory-operations.operational-views.5d" + ], + "desc": "Rank signed-out recommendations without purchase counts.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": "const purchaseCountOf = (id: bigint) => ctx.db.itemStats.itemId.find(id)?.purchaseCount ?? 0;", + "replace": "const purchaseCountOf = (_id: bigint) => 0;" + } + ] + }, + { + "id": "queue-warehouse-reports-west", + "scenario": "tracks/ecommerce/scenarios/02-queue-warehouse.json", + "targets": [ + "ecommerce.operations-access.fulfilment-queue.1b" + ], + "desc": "The queue renders West for the deterministic Desk Lamp allocation even though the order reserved stock in East.", + "file": "client/src/components/FulfilmentPanel.tsx", + "edits": [ + { + "find": "{name}: {order.warehouseNames[i]}", + "replace": "{name}: West" + } + ] + }, + { + "id": "transfer-creates-stock-during-race", + "scenario": "tracks/ecommerce/scenarios/02-server-actions.json", + "targets": [ + "ecommerce.inventory-operations.stock-conservation.202d" + ], + "desc": "The transfer reducer credits the destination one unit more than it debits from the source, so the item's total after a transfer racing a purchase is the starting total rather than one less. A stored conservation defect; it does not model a lost-update interleaving because SpacetimeDB reducer execution is atomically serialized.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": " ctx.db.stock.insert({ ...toRow, quantity: toRow.quantity + quantity });", + "replace": " ctx.db.stock.insert({ ...toRow, quantity: toRow.quantity + quantity + 1 });" + } + ] + }, + { + "id": "catalog-search-ignores-the-query", + "scenario": "tracks/ecommerce/scenarios/01-catalog-search.json", + "targets": [ + "ecommerce.feature.catalog.catalog-search.2d" + ], + "desc": "A non-empty catalog query filters out every product instead of matching names.", + "file": "client/src/App.tsx", + "edits": [ + { + "find": ".filter(item => !q || item.name.toLowerCase().includes(q))", + "replace": ".filter(() => !q) // mutant: non-empty searches return no products" + } + ] + }, + { + "id": "admin-total-stock-is-not-rendered", + "scenario": "tracks/ecommerce/scenarios/01-warehouse-stock-live-staff.json", + "targets": [ + "ecommerce.spec.live-state.warehouse-stock.7c" + ], + "desc": "The staff stock total always renders zero after a warehouse restock.", + "file": "client/src/components/AdminPanel.tsx", + "edits": [ + { + "find": "{totalStockOf(item.id)}", + "replace": "{0}" + } + ] + }, + { + "id": "customers-can-schedule-restocks", + "scenario": "tracks/ecommerce/scenarios/03-deferred-access.json", + "targets": [ + "ecommerce.l3.deferred-access.scheduled-work-access.317a" + ], + "desc": "Scheduling a restock no longer checks that the caller is an administrator.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": " (ctx, input) => {\n requireAdmin(ctx);\n const itemName = input.item.trim();\n const warehouseName = input.warehouse.trim();\n const item = [...ctx.db.item].find(row => row.name === itemName);\n const warehouse = [...ctx.db.warehouse].find(row => row.name === warehouseName);", + "replace": " (ctx, input) => {\n // mutant: any signed-in or anonymous caller can schedule work\n const itemName = input.item.trim();\n const warehouseName = input.warehouse.trim();\n const item = [...ctx.db.item].find(row => row.name === itemName);\n const warehouse = [...ctx.db.warehouse].find(row => row.name === warehouseName);" + } + ] + }, + { + "id": "scheduled-restock-execution-queue-is-process-local", + "scenario": "tracks/ecommerce/scenarios/03-deferred-durability.json", + "targets": [ + "ecommerce.l3.deferred-durability.restart-survival.311a" + ], + "desc": "Keep manual restock execution IDs only in the V8 process. Ordinary timers work, but restart loses the execution queue while pending rows remain. Isolate replacement can also lose this queue.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": "export const scheduleRestock = spacetimedb.reducer(", + "replace": "const pendingRestockExecution = new Set();\n\nexport const scheduleRestock = spacetimedb.reducer(" + }, + { + "find": " ctx.db.scheduledRestock.insert({\n id: 0n,\n itemId: item.id,\n warehouseId: warehouse.id,\n quantity: input.quantity,\n dueMicros: nowMicros(ctx) + BigInt(input.delaySeconds) * SECOND,\n status: 'pending',\n reorderRuleId: undefined,\n });", + "replace": " const pending = ctx.db.scheduledRestock.insert({\n id: 0n,\n itemId: item.id,\n warehouseId: warehouse.id,\n quantity: input.quantity,\n dueMicros: nowMicros(ctx) + BigInt(input.delaySeconds) * SECOND,\n status: 'pending',\n reorderRuleId: undefined,\n });\n pendingRestockExecution.add(pending.id);" + }, + { + "find": " if (pending.status !== 'pending' || pending.dueMicros > now) continue;\n restoreStock(ctx, pending.itemId, pending.warehouseId, pending.quantity);", + "replace": " if (pending.status !== 'pending' || pending.dueMicros > now) continue;\n if (pending.reorderRuleId === undefined && !pendingRestockExecution.delete(pending.id)) continue;\n restoreStock(ctx, pending.itemId, pending.warehouseId, pending.quantity);" + } + ] + }, + { + "id": "reservation-is-delayed-past-the-durability-window", + "scenario": "tracks/ecommerce/scenarios/03-deferred-durability.json", + "targets": [ + "ecommerce.l3.deferred-durability.restart-survival.314a" + ], + "desc": "A reservation is persisted with a ten-minute lifetime instead of ninety seconds.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": "const expiresMicros = nowMicros(ctx) + 90n * SECOND;", + "replace": "const expiresMicros = nowMicros(ctx) + 600n * SECOND;" + } + ] + }, + { + "id": "completed-restock-remains-pending", + "scenario": "tracks/ecommerce/scenarios/03-deferred-integrity.json", + "targets": [ + "ecommerce.l3.deferred-integrity.exactly-once.311a" + ], + "desc": "A completed restock remains pending and is applied again by later maintenance ticks.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": "ctx.db.scheduledRestock.id.update({ ...pending, status: 'complete' });", + "replace": "ctx.db.scheduledRestock.id.update({ ...pending, status: 'pending' });" + } + ] + }, + { + "id": "reservation-expiry-restores-stock-twice", + "scenario": "tracks/ecommerce/scenarios/03-deferred-integrity.json", + "targets": [ + "ecommerce.l3.deferred-integrity.stock-conservation.313a" + ], + "desc": "Reservation expiry returns twice the quantity that was reserved.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": "restoreStock(ctx, row.stockItemId || row.itemId, row.warehouseId, row.quantity);\n ctx.db.reservation.id.update({ ...row, expired: true });", + "replace": "restoreStock(ctx, row.stockItemId || row.itemId, row.warehouseId, row.quantity * 2);\n ctx.db.reservation.id.update({ ...row, expired: true });" + } + ] + }, + { + "id": "checkout-takes-reserved-stock-again", + "scenario": "tracks/ecommerce/scenarios/03-deferred-integrity.json", + "targets": [ + "ecommerce.l3.deferred-integrity.stock-conservation.314a" + ], + "desc": "Checkout decrements stock after the cart reservation already took it.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": "const allocations = held.map(row => ({ warehouseId: row.warehouseId, quantity: row.quantity, stockItemId: row.stockItemId }));\n const orderItemRow", + "replace": "const allocations = decrementStockTracked(ctx, p.itemId, p.quantity);\n const orderItemRow" + } + ] + }, + { + "id": "reservation-does-not-decrement-stock", + "scenario": "tracks/ecommerce/scenarios/03-reservations.json", + "targets": [ + "ecommerce.l3.reservations.reservations.301a" + ], + "desc": "Creating a reservation leaves the public stock total unchanged.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": "ctx.db.stock.insert({ ...row, quantity: row.quantity - allocation.quantity });", + "replace": "ctx.db.stock.insert({ ...row, quantity: row.quantity });" + } + ] + }, + { + "id": "reservation-timer-is-static", + "scenario": "tracks/ecommerce/scenarios/03-reservations.json", + "targets": [ + "ecommerce.l3.reservations.reservations.305a" + ], + "desc": "The cart always renders ninety seconds instead of a decreasing reservation timer.", + "file": "client/src/components/CartPanel.tsx", + "edits": [ + { + "find": "const seconds = Math.max(0, Number((reservation.expiresMicros - BigInt(Date.now()) * 1000n) / 1_000_000n));", + "replace": "const seconds = 90;" + } + ] + }, + { + "id": "checkout-leaves-cart-lines", + "scenario": "tracks/ecommerce/scenarios/03-reservations.json", + "targets": [ + "ecommerce.l3.reservations.reservations.306a" + ], + "desc": "Checkout creates an order but leaves the purchased lines in the cart.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": "for (const line of lines) ctx.db.cartItem.id.delete(line.id);", + "replace": "for (const line of lines) void line;" + } + ] + }, + { + "id": "expired-reservation-is-still-marked-live", + "scenario": "tracks/ecommerce/scenarios/03-reservations.json", + "targets": [ + "ecommerce.l3.reservations.reservations.307a" + ], + "desc": "Expired reservations keep their live flag, so the cart does not mark them expired.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": "ctx.db.reservation.id.update({ ...row, expired: true });", + "replace": "ctx.db.reservation.id.update({ ...row, expired: false });" + } + ] + }, + { + "id": "renewed-reservation-expires-too-soon", + "scenario": "tracks/ecommerce/scenarios/03-reservations.json", + "targets": [ + "ecommerce.l3.reservations.reservations.308a" + ], + "desc": "Renewed quantities receive only a twenty-second reservation window.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": "reserveUnits(ctx, accountId, itemId, quantity);", + "replace": "reserveUnits(ctx, accountId, itemId, quantity);\n for (const renewed of findReservations(ctx, accountId, itemId)) {\n ctx.db.reservation.id.update({ ...renewed, expiresMicros: nowMicros(ctx) + 20n * SECOND });\n }" + } + ] + }, + { + "id": "pending-restock-timer-is-static", + "scenario": "tracks/ecommerce/scenarios/03-scheduled-restocks.json", + "targets": [ + "ecommerce.l3.scheduled-restocks.scheduled-restocks.302a" + ], + "desc": "The pending restock UI always renders ninety seconds instead of the server due time.", + "file": "client/src/components/ProgressionWorkbench.tsx", + "edits": [ + { + "find": "{Math.max(0, Number((row.dueMicros - BigInt(Date.now()) * 1000n) / 1_000_000n))}", + "replace": "{90}" + } + ] + }, + { + "id": "due-restock-omits-ledger-entry", + "scenario": "tracks/ecommerce/scenarios/03-scheduled-restock-apply.json", + "targets": [ + "ecommerce.l3.scheduled-restocks.scheduled-restocks.305a" + ], + "desc": "A due restock updates stock but does not create its stock ledger record.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": "ctx.db.stockLedger.insert({\n id: 0n,\n itemId: pending.itemId,\n warehouseId: pending.warehouseId,\n quantity: pending.quantity,\n createdMicros: now,\n source: 'scheduled restock',\n });", + "replace": "// mutant: due restocks are not recorded in the ledger" + } + ] + }, + { + "id": "cancelled-restock-remains-pending", + "scenario": "tracks/ecommerce/scenarios/03-scheduled-restock-cancel.json", + "targets": [ + "ecommerce.l3.scheduled-restocks.scheduled-restocks.306a" + ], + "desc": "Cancelling a restock leaves it pending, so maintenance later applies it.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": "ctx.db.scheduledRestock.id.update({ ...row, status: 'cancelled' });", + "replace": "ctx.db.scheduledRestock.id.update({ ...row, status: 'pending' });" + } + ] + }, + { + "id": "restart-restock-runs-early", + "scenario": "tracks/ecommerce/scenarios/03-server-time.json", + "targets": [ + "ecommerce.l3.server-time.server-time.312a" + ], + "desc": "A scheduled restock ignores its requested delay and becomes due after one second.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": "dueMicros: nowMicros(ctx) + BigInt(input.delaySeconds) * SECOND,", + "replace": "dueMicros: nowMicros(ctx) + SECOND," + } + ] + }, + { + "id": "closed-browser-reservation-never-expires", + "scenario": "tracks/ecommerce/scenarios/03-server-time.json", + "targets": [ + "ecommerce.l3.server-time.server-time.313a" + ], + "desc": "Server maintenance skips reservation expiry when no customer browser is present.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": "for (const row of [...ctx.db.reservation.iter()]) {\n if (row.expired || row.expiresMicros > now) continue;", + "replace": "for (const row of [...ctx.db.reservation.iter()].filter(() => false)) {\n if (row.expired || row.expiresMicros > now) continue;" + } + ] + }, + { + "id": "catalog-product-is-not-published", + "scenario": "tracks/ecommerce/scenarios/progression-catalog-management.json", + "targets": [ + "ecommerce.progression.catalog-management.catalog-management.622a", + "ecommerce.progression.catalog-management.catalog-management.622b" + ], + "desc": "The public product card omits the submitted name. Both create visibility and variant navigation locate the submitted product card by its name, so the hidden name prevents both required observations.", + "file": "client/src/components/ItemCard.tsx", + "edits": [ + { + "find": "{item.name}", + "replace": "{item.name === 'Travel Mug' ? '' : item.name}" + } + ] + }, + { + "id": "catalog-variants-are-discarded", + "scenario": "tracks/ecommerce/scenarios/progression-catalog-management.json", + "targets": [ + "ecommerce.progression.catalog-management.catalog-management.622b" + ], + "desc": "Catalog management discards every submitted product variant.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": "for (const variantName of variants.split(',').map(value => value.trim()).filter(Boolean)) {\n ctx.db.itemVariant.insert({ id: 0n, itemId: product.id, name: variantName });\n }", + "replace": "void variants; // mutant: submitted variants are discarded" + } + ] + }, + { + "id": "profile-is-lost-on-fresh-account-login", + "scenario": "tracks/ecommerce/scenarios/progression-customer-profile.json", + "targets": [ + "ecommerce.spec.state-durability.customer-profile-reload.620a" + ], + "desc": "Delete a saved profile when its owner signs in from a new transport identity. Initial save, same-identity reload, and the independent privacy owner remain intact.", + "file": "backend/spacetimedb/src/auth.ts", + "edits": [ + { + "find": " if (!current || current.passwordHash !== account.passwordHash) return false;\n bindSession(tx, account.id);", + "replace": " if (!current || current.passwordHash !== account.passwordHash) return false;\n tx.db.customerProfile.accountId.delete(account.id);\n bindSession(tx, account.id);" + } + ] + }, + { + "id": "customer-profile-view-leaks-another-account", + "scenario": "tracks/ecommerce/scenarios/progression-customer-profile.json", + "targets": [ + "ecommerce.spec.access-control.customer-profile-privacy.620b" + ], + "desc": "The customer profile view returns the first stored profile without checking its owner.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": "return accountId === null ? undefined : ctx.db.customerProfile.accountId.find(accountId) ?? undefined;", + "replace": "return accountId === null ? undefined : [...ctx.db.customerProfile.iter()][0];" + } + ] + }, + { + "id": "faceted-search-ignores-category", + "scenario": "tracks/ecommerce/scenarios/progression-faceted-filters.json", + "targets": [ + "ecommerce.progression.faceted-search.faceted-search.401a" + ], + "desc": "Faceted search applies price and stock filters but ignores the selected category.", + "file": "client/src/App.tsx", + "edits": [ + { + "find": ".filter(item => !categoryFilter || categoryByItem.get(item.id) === categoryFilter)", + "replace": ".filter(() => true) // mutant: category filter is ignored" + } + ] + }, + { + "id": "active-search-uses-purchase-ranking", + "scenario": "tracks/ecommerce/scenarios/progression-search-ordering.json", + "targets": [ + "ecommerce.spec.search-ordering.search-ordering.402b" + ], + "desc": "Keep purchase ranking when search text or filters are active.", + "file": "client/src/App.tsx", + "edits": [ + { + "find": "const catalogItems = showingSearch ? filteredSearchResults : rankedItems;", + "replace": "const catalogItems = rankedItems;" + } + ] + }, + { + "id": "faceted-search-next-page-does-not-advance", + "scenario": "tracks/ecommerce/scenarios/progression-faceted-pagination.json", + "targets": [ + "ecommerce.progression.faceted-search.faceted-search.402a" + ], + "desc": "The next-page control keeps the search on its current page.", + "file": "client/src/App.tsx", + "edits": [ + { + "find": "onClick={() => setSearchPage(page => page + 1)}>Next", + "replace": "onClick={() => setSearchPage(page => page)}>Next" + } + ] + }, + { + "id": "managed-support-leaks-and-accepts-cross-account-replies", + "scenario": "tracks/ecommerce/scenarios/progression-managed-support-privacy.json", + "targets": [ + "ecommerce.spec.access-control.managed-support-privacy.613b" + ], + "desc": "Managed support tickets are visible across accounts and replayed replies are accepted.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": ".filter(row => isGuestTicketCreator(sender, row.creatorIdentity.toHexString(), row.accountId) ||\n !!actor && (actor.isAdmin || actor.isStaff || row.accountId === accountId))", + "replace": ".filter(() => true)" + }, + { + "file": "backend/spacetimedb/src/index.ts", + "find": "if (!actor.isAdmin && !actor.isStaff && ticket.accountId !== actor.id) {\n throw new SenderError('That support ticket is private.');\n }", + "replace": "// mutant: any signed-in account can access any support ticket" + } + ] + }, + { + "id": "managed-support-replies-are-empty", + "scenario": "tracks/ecommerce/scenarios/progression-managed-support-shared.json", + "targets": [ + "ecommerce.spec.live-state.managed-support.613a", + "ecommerce.progression.managed-support.managed-support.613c" + ], + "desc": "Managed support stores replies without their message body. Both the ordinary reply and shared-live reply assertions require the stored message body; neither can pass an empty reply.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": "body: body.trim(),\n createdMicros: nowMicros(ctx),", + "replace": "body: '',\n createdMicros: nowMicros(ctx)," + } + ] + }, + { + "id": "managed-support-live-replies-stay-at-initial-snapshot", + "scenario": "tracks/ecommerce/scenarios/progression-managed-support-shared.json", + "targets": [ + "ecommerce.spec.live-state.managed-support.613a" + ], + "desc": "Keep the initial subscribed reply snapshot on each page. Reducers still save replies, and a reload shows them, but later replies do not reach the rendered conversation live.", + "file": "client/src/App.tsx", + "edits": [ + { + "find": " const [supportReplyRows] = useTable(tables.visibleSupportReplies);", + "replace": " const [liveSupportReplyRows, supportRepliesReady] = useTable(tables.visibleSupportReplies);\n const supportReplyRows = useMemo(() => [...liveSupportReplyRows], [supportRepliesReady]);" + } + ] + }, + { + "id": "notification-preferences-are-not-saved", + "scenario": "tracks/ecommerce/scenarios/progression-notification-preferences.json", + "targets": [ + "ecommerce.spec.state-durability.notification-preferences-reload.630a" + ], + "desc": "Saving notification preferences discards the selected values.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": "if (existing) ctx.db.notificationPreference.accountId.update(row);\n else ctx.db.notificationPreference.insert(row);", + "replace": "void existing;\n void row; // mutant: notification preferences are discarded" + } + ] + }, + { + "id": "notification-preferences-leak-across-accounts", + "scenario": "tracks/ecommerce/scenarios/progression-notification-preferences.json", + "targets": [ + "ecommerce.spec.access-control.notification-preferences-privacy.630b" + ], + "desc": "The preference view returns another account's first stored choice.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": "const row = ctx.db.notificationPreference.accountId.find(accountId);\n return row ? { orderEnabled: row.orderEnabled, stockEnabled: row.stockEnabled } : undefined;", + "replace": "const row = [...ctx.db.notificationPreference.iter()][0];\n return row ? { orderEnabled: row.orderEnabled, stockEnabled: row.stockEnabled } : undefined;" + } + ] + }, + { + "id": "checkout-records-zero-payment", + "scenario": "tracks/ecommerce/scenarios/progression-core-business.json", + "targets": [ + "ecommerce.progression.payment-records.payment-records.623a" + ], + "desc": "Checkout records a paid payment with a zero amount.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": "ctx.db.paymentRecord.insert({ id: 0n, orderId: order.id, amount: order.total, status: 'paid' });\n if (promo) {", + "replace": "ctx.db.paymentRecord.insert({ id: 0n, orderId: order.id, amount: 0, status: 'paid' });\n if (promo) {" + } + ] + }, + { + "id": "checkout-records-duplicate-payments", + "scenario": "tracks/ecommerce/scenarios/progression-core-business.json", + "targets": [ + "ecommerce.spec.transactional-integrity.payment-deduplication.623b" + ], + "desc": "Checkout inserts two payment records for one order.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": "ctx.db.paymentRecord.insert({ id: 0n, orderId: order.id, amount: order.total, status: 'paid' });\n if (promo) {", + "replace": "ctx.db.paymentRecord.insert({ id: 0n, orderId: order.id, amount: order.total, status: 'paid' });\n ctx.db.paymentRecord.insert({ id: 0n, orderId: order.id, amount: order.total + 0.01, status: 'paid' });\n if (promo) {" + } + ] + }, + { + "id": "active-promotion-does-not-discount-checkout", + "scenario": "tracks/ecommerce/scenarios/progression-promotion-checkout.json", + "targets": [ + "ecommerce.progression.promotion-checkout.promotion-checkout-active.621a" + ], + "desc": "Checkout ignores an active promotion when it calculates the discount.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": "const discount = promo ? total * (promo.discountPercent / 100) : 0;", + "replace": "const discount = 0;" + } + ] + }, + { + "id": "expired-promotion-is-accepted", + "scenario": "tracks/ecommerce/scenarios/progression-promotion-checkout.json", + "targets": [ + "ecommerce.progression.promotion-checkout.promotion-checkout-expired.621b" + ], + "desc": "Promotion application does not reject a promotion after its end time.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": "if (!promo || promo.startMicros > now || promo.endMicros < now || promo.redemptions >= promo.usageLimit) {", + "replace": "if (!promo || promo.startMicros > now || promo.redemptions >= promo.usageLimit) {" + } + ] + }, + { + "id": "exhausted-promotion-is-accepted", + "scenario": "tracks/ecommerce/scenarios/progression-promotion-checkout.json", + "targets": [ + "ecommerce.progression.promotion-checkout.promotion-checkout-exhausted.621c" + ], + "desc": "Promotion application does not reject a promotion at its usage limit.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": "if (!promo || promo.startMicros > now || promo.endMicros < now || promo.redemptions >= promo.usageLimit) {", + "replace": "if (!promo || promo.startMicros > now || promo.endMicros < now) {" + } + ] + }, + { + "id": "customers-can-create-promotions", + "scenario": "tracks/ecommerce/scenarios/progression-promotion-rules.json", + "targets": [ + "ecommerce.spec.access-control.promotion-management-boundary.620b" + ], + "desc": "Promotion creation does not require staff access.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": " (ctx, input) => {\n requireStaffOrAdmin(ctx);\n if (input.discountPercent <= 0 || input.discountPercent > 100) {", + "replace": " (ctx, input) => {\n if (input.discountPercent <= 0 || input.discountPercent > 100) {" + } + ] + }, + { + "id": "promotion-rule-stores-the-wrong-discount", + "scenario": "tracks/ecommerce/scenarios/progression-promotion-rules.json", + "targets": [ + "ecommerce.progression.promotion-rules.promotion-rule-values.620a" + ], + "desc": "Promotion creation stores a one-percent discount instead of the submitted value.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": "ctx.db.promotion.insert({ id: 0n, ...input, code: input.code.trim(), redemptions: 0 });", + "replace": "ctx.db.promotion.insert({ id: 0n, ...input, discountPercent: 1, code: input.code.trim(), redemptions: 0 });" + } + ] + }, + { + "id": "staff-cannot-open-staff-tools", + "scenario": "tracks/ecommerce/scenarios/progression-staff-access.json", + "targets": [ + "ecommerce.progression.staff-access.staff-access.601a" + ], + "desc": "Deny administrators entry to staff tools while keeping ordinary staff access working.", + "file": "client/src/App.tsx", + "edits": [ + { + "find": "{(isStaff || isAdmin) && (\n ({", + "replace": "return [...ctx.db.notification.iter()].map(row => ({" + } + ] + }, + { + "id": "support-history-is-lost-on-fresh-account-login", + "scenario": "tracks/ecommerce/scenarios/progression-support-history.json", + "targets": [ + "ecommerce.spec.state-durability.support-history-reload.612a" + ], + "desc": "Resolve customer support ownership by transport identity only, omitting the account ownership path. Initial submission, same-identity reload, and stored tickets remain intact; fresh account login cannot recover the history.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": "!!actor && (actor.isAdmin || actor.isStaff || row.accountId === accountId))", + "replace": "!!actor && (actor.isAdmin || actor.isStaff || row.creatorIdentity.toHexString() === sender))" + } + ] + }, + { + "id": "support-history-leaks-across-customers", + "scenario": "tracks/ecommerce/scenarios/progression-support-history.json", + "targets": [ + "ecommerce.spec.access-control.support-history-privacy.612b", + "ecommerce.spec.access-control.support-history-logout.612d" + ], + "desc": "Return all support tickets, exposing them to other customers and signed-out visitors.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": ".filter(row => isGuestTicketCreator(sender, row.creatorIdentity.toHexString(), row.accountId) ||\n !!actor && (actor.isAdmin || actor.isStaff || row.accountId === accountId))", + "replace": ".filter(() => true)" + } + ] + }, + { + "id": "visitor-support-reference-is-hidden", + "scenario": "tracks/ecommerce/scenarios/progression-support-intake.json", + "targets": [ + "ecommerce.progression.support-intake.support-intake.610a" + ], + "desc": "A visitor can create a support ticket but the returned reference is not rendered.", + "file": "client/src/components/ProgressionWorkbench.tsx", + "edits": [ + { + "find": "
{supportReference}
", + "replace": "
" + } + ] + }, + { + "id": "support-assignment-is-discarded", + "scenario": "tracks/ecommerce/scenarios/progression-support-triage.json", + "targets": [ + "ecommerce.progression.support-triage.support-assignment.611a" + ], + "desc": "Support triage saves status and priority but discards the assignee.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": "ctx.db.supportTicket.id.update({ ...ticket, assigneeId: nextAssigneeId, priority, status });", + "replace": "ctx.db.supportTicket.id.update({ ...ticket, assigneeId: undefined, priority, status });" + } + ] + }, + { + "id": "support-priority-is-discarded", + "scenario": "tracks/ecommerce/scenarios/progression-support-triage.json", + "targets": [ + "ecommerce.progression.support-triage.support-priority.611b" + ], + "desc": "Support triage always saves normal priority instead of the submitted value.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": "ctx.db.supportTicket.id.update({ ...ticket, assigneeId: nextAssigneeId, priority, status });", + "replace": "ctx.db.supportTicket.id.update({ ...ticket, assigneeId: nextAssigneeId, priority: 'normal', status });" + } + ] + }, + { + "id": "support-status-is-discarded", + "scenario": "tracks/ecommerce/scenarios/progression-support-triage.json", + "targets": [ + "ecommerce.progression.support-triage.support-status.611c" + ], + "desc": "Support triage preserves the old status instead of the submitted value.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": "ctx.db.supportTicket.id.update({ ...ticket, assigneeId: nextAssigneeId, priority, status });", + "replace": "ctx.db.supportTicket.id.update({ ...ticket, assigneeId: nextAssigneeId, priority, status: ticket.status });" + } + ] + }, + { + "id": "nonpositive-cart-quantity-is-treated-as-removal", + "scenario": "tracks/ecommerce/scenarios/01-cart-boundary.json", + "targets": [ + "ecommerce.spec.access-control.cart-boundary.109b" + ], + "desc": "Accept a negative quantity and remove the cart line instead of refusing the request.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": " if (quantity < 1) throw new SenderError('Quantity must be at least 1.');\n const existing = findCartLine(ctx, acc.id, itemId);\n if (!existing) throw new SenderError('That item is not in your cart.');\n if (existing.bundlePrice > 0) throw new SenderError('Remove and re-add a whole bundle.');\n replaceReservation(ctx, acc.id, itemId, quantity);\n ctx.db.cartItem.id.update({ ...existing, quantity });", + "replace": " const existing = findCartLine(ctx, acc.id, itemId);\n if (!existing) throw new SenderError('That item is not in your cart.');\n if (quantity < 1) {\n ctx.db.cartItem.id.delete(existing.id);\n return;\n }\n if (existing.bundlePrice > 0) throw new SenderError('Remove and re-add a whole bundle.');\n replaceReservation(ctx, acc.id, itemId, quantity);\n ctx.db.cartItem.id.update({ ...existing, quantity });" + } + ] + }, + { + "id": "admin-restock-preserves-existing-stock", + "scenario": "tracks/ecommerce/scenarios/01-warehouse-stock-live-staff.json", + "targets": [ + "ecommerce.spec.live-state.warehouse-stock.7c" + ], + "desc": "Accept an administrator restock but write the existing quantity back unchanged.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": " ctx.db.stock.insert({ ...existing, quantity: existing.quantity + quantity });", + "replace": " ctx.db.stock.insert({ ...existing, quantity: existing.quantity });" + } + ] + }, + { + "id": "operator-authorization-allows-customer-price-change", + "scenario": "tracks/ecommerce/scenarios/02-strengthened.json", + "targets": [ + "ecommerce.operations-access.operator-authorization.201b" + ], + "desc": "The price reducer drops its administrator role gate.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": " (ctx, { itemId, price }) => {\n requireAdmin(ctx);", + "replace": " (ctx, { itemId, price }) => {\n // mutant: no administrator role check" + } + ] + }, + { + "id": "fulfilment-queue-allows-customer-shipping", + "scenario": "tracks/ecommerce/scenarios/02-self-contained.json", + "targets": [ + "ecommerce.operations-access.fulfilment-queue.1e" + ], + "desc": "The shipping reducer drops the staff role check while retaining the pending-order guard.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": "export const shipOrder = spacetimedb.reducer({ orderId: t.u64() }, (ctx, { orderId }) => {\n requireStaffOrAdmin(ctx);", + "replace": "export const shipOrder = spacetimedb.reducer({ orderId: t.u64() }, (ctx, { orderId }) => {\n // mutant: no staff role check" + } + ] + }, + { + "id": "catalog-search-keeps-pre-change-price", + "scenario": "tracks/ecommerce/scenarios/02-live-price.json", + "targets": [ + "ecommerce.returns-pricing.price-history.4b" + ], + "desc": "The search result renderer caches each item's first visible price and ignores later live price updates.", + "file": "client/src/components/ItemCard.tsx", + "edits": [ + { + "find": "import { ItemRow } from '../types';", + "replace": "import { useRef } from 'react';\nimport { ItemRow } from '../types';" + }, + { + "find": " const outOfStock = stock <= 0;\n const lowStock = !outOfStock && stock <= 5;", + "replace": " const outOfStock = stock <= 0;\n const lowStock = !outOfStock && stock <= 5;\n // mutant: the card retains the first price it renders\n const firstPrice = useRef(item.price);" + }, + { + "find": " {formatMoney(item.price)}", + "replace": " {formatMoney(firstPrice.current)}" + } + ] + }, + { + "id": "open-cart-keeps-pre-change-price", + "scenario": "tracks/ecommerce/scenarios/progression-price-cart-checkout.json", + "targets": [ + "ecommerce.returns-pricing.price-history.4c" + ], + "desc": "The open-cart memo ignores reactive item-table price updates while checkout still reads the current server price.", + "file": "client/src/App.tsx", + "edits": [ + { + "find": " [cartRows, items, stockByItem]", + "replace": " [cartRows, stockByItem]" + } + ] + }, + { + "id": "catalog-price-rewrites-receipts", + "scenario": "tracks/ecommerce/scenarios/02-paid-price-history.json", + "targets": [ + "ecommerce.returns-pricing.price-history.4a" + ], + "desc": "Changing a catalog price cascades into saved order lines and recomputes historical order totals inside the reducer transaction.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": " ctx.db.item.id.update({ ...it, price });", + "replace": " ctx.db.item.id.update({ ...it, price });\n const repricedOrderIds = new Set();\n for (const line of ctx.db.orderItem.iter()) {\n if (line.itemId !== itemId) continue;\n ctx.db.orderItem.id.update({ ...line, unitPrice: price });\n repricedOrderIds.add(line.orderId);\n }\n for (const orderId of repricedOrderIds) {\n const historical = ctx.db.customerOrder.id.find(orderId);\n if (!historical) continue;\n let total = 0;\n for (const line of ctx.db.orderItem.orderId.filter(orderId)) total += line.unitPrice * line.quantity;\n ctx.db.customerOrder.id.update({ ...historical, total });\n }" + } + ] + }, + { + "id": "catalog-price-rewrites-earned-revenue", + "scenario": "tracks/ecommerce/scenarios/02-invariants.json", + "targets": [ + "ecommerce.returns-pricing.refund-accounting.203b" + ], + "desc": "Changing a catalog price cascades into saved order lines and recomputes historical order totals and revenue inside the reducer transaction.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": " ctx.db.item.id.update({ ...it, price });", + "replace": " ctx.db.item.id.update({ ...it, price });\n const repricedOrderIds = new Set();\n for (const line of ctx.db.orderItem.iter()) {\n if (line.itemId !== itemId) continue;\n ctx.db.orderItem.id.update({ ...line, unitPrice: price });\n repricedOrderIds.add(line.orderId);\n }\n for (const orderId of repricedOrderIds) {\n const historical = ctx.db.customerOrder.id.find(orderId);\n if (!historical) continue;\n let total = 0;\n for (const line of ctx.db.orderItem.orderId.filter(orderId)) total += line.unitPrice * line.quantity;\n ctx.db.customerOrder.id.update({ ...historical, total });\n }" + } + ] + }, + { + "id": "returned-line-marker-omitted", + "scenario": "tracks/ecommerce/scenarios/02-strengthened.json", + "targets": [ + "ecommerce.returns-pricing.cancellation-and-return.3c" + ], + "desc": "A returned order line keeps its persisted returned state, restored stock, and adjusted revenue but omits the visible returned marker.", + "file": "client/src/components/OrdersPanel.tsx", + "edits": [ + { + "find": "{item.returned && Returned}", + "replace": "{false && Returned}" + } + ] + }, + { + "id": "direct-review-access-is-not-checked", + "scenario": "tracks/ecommerce/scenarios/progression-review-access.json", + "targets": [ + "ecommerce.progression.review-access-specifications.review-eligibility-direct.618a" + ], + "desc": "The direct review action accepts a review from a customer who did not buy the item.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": " if (!bought) throw new SenderError('You can only review items you have purchased.');", + "replace": " // mutant: purchase eligibility is not checked" + } + ] + }, + { + "id": "support-history-rows-are-hidden", + "scenario": "tracks/ecommerce/scenarios/progression-support-history.json", + "targets": [ + "ecommerce.progression.support-history.support-history.612c", + "ecommerce.spec.state-durability.support-history-reload.612a", + "ecommerce.spec.access-control.support-history-privacy.612b", + "ecommerce.spec.access-control.support-history-logout.612d" + ], + "desc": "Hide submitted support ticket rows while leaving the submission reference available. History, reload, privacy, and logout require the owner to see the ticket first. This breaks those positive observations; it does not create a privacy leak or remove stored data.", + "file": "client/src/components/ProgressionWorkbench.tsx", + "edits": [ + { + "find": "data-role=\"support-ticket\"", + "replace": "data-role=\"support-ticket\" style={{ display: \"none\" }}" + } + ] + }, + { + "id": "authorized-restock-does-not-change-stock", + "scenario": "tracks/ecommerce/scenarios/01-admin-write-staff.json", + "targets": [ + "ecommerce.feature.warehouse-admin.admin-write.103a" + ], + "desc": "Accept an administrator restock without changing warehouse stock.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": " if (existing) {\n ctx.db.stock.by_item_warehouse.delete([itemId, warehouseId]);\n ctx.db.stock.insert({ ...existing, quantity: existing.quantity + quantity });\n } else {\n ctx.db.stock.insert({ item_id: itemId, warehouse_id: warehouseId, quantity });\n }\n", + "replace": " // mutant: accept restock without changing stock\n" + } + ] + }, + { + "id": "low-stock-threshold-is-two-units", + "scenario": "tracks/ecommerce/scenarios/02-low-stock.json", + "targets": [ + "ecommerce.inventory-operations.operational-views.5e", + "ecommerce.spec.live-state.inventory-dashboard.5a" + ], + "desc": "The dashboard lists only items with two units or fewer, so the seeded three-unit item is missing from the low-stock view. The live check in the same scenario opens with the identical observation and necessarily fails with it.", + "file": "client/src/App.tsx", + "edits": [ + { + "find": "const LOW_STOCK_THRESHOLD = 10;", + "replace": "const LOW_STOCK_THRESHOLD = 2;" + } + ] + }, + { + "id": "category-totals-count-only-since-the-dashboard-opened", + "scenario": "tracks/ecommerce/scenarios/02-operational-category-totals.json", + "targets": [ + "ecommerce.inventory-operations.operational-views.5f" + ], + "desc": "The category table shows units and revenue accumulated since the dashboard was opened instead of the stored totals, so a reload resets both to zero and the totals recorded before the reload are not reproduced. Live movement within one open dashboard is still correct, so the live check is unaffected.", + "file": "client/src/components/AdminPanel.tsx", + "edits": [ + { + "find": "import { useState } from 'react';", + "replace": "import { useRef, useState } from 'react';" + }, + { + "find": " return (\n
", + "replace": " const openingTotals = useRef | null>(null);\n if (openingTotals.current === null && categoryTotals.length > 0) {\n openingTotals.current = new Map(\n categoryTotals.map((cat): [bigint, { units: number; revenue: number }] => [\n cat.categoryId,\n { units: cat.unitsSold, revenue: cat.revenue },\n ])\n );\n }\n const sessionTotals = categoryTotals.map((cat) => {\n const opening = openingTotals.current?.get(cat.categoryId);\n return {\n ...cat,\n unitsSold: cat.unitsSold - (opening?.units ?? 0),\n revenue: cat.revenue - (opening?.revenue ?? 0),\n };\n });\n\n return (\n
" + }, + { + "find": " {categoryTotals.map((cat) => (", + "replace": " {sessionTotals.map((cat) => (" + } + ] + }, + { + "id": "profile-summary-ignores-a-profile-saved-this-session", + "scenario": "tracks/ecommerce/scenarios/progression-customer-profile.json", + "targets": [ + "ecommerce.progression.customer-profile.customer-profile.620c" + ], + "desc": "Hide the profile summary immediately after saving in the current view. Stored profile data and a reopened or reloaded view remain correct, so fresh-login durability and privacy positive controls remain observable.", + "file": "client/src/components/ProgressionWorkbench.tsx", + "edits": [ + { + "find": " const [profileName, setProfileName] = useState(profile?.name ?? '');", + "replace": " const [profileName, setProfileName] = useState(profile?.name ?? '');\n const [profileSavedHere, setProfileSavedHere] = useState(false);" + }, + { + "find": "onClick={() => reducers?.saveProfile({ name: profileName, address: profileAddress })}", + "replace": "onClick={() => { setProfileSavedHere(true); return reducers?.saveProfile({ name: profileName, address: profileAddress }); }}" + }, + { + "find": "
{profile?.name} {profile?.address}
", + "replace": "
{!profileSavedHere && <>{profile?.name} {profile?.address}}
" + } + ] + }, + { + "id": "stored-support-replies-are-hidden-after-reload", + "scenario": "tracks/ecommerce/scenarios/progression-managed-support-shared.json", + "targets": [ + "ecommerce.progression.managed-support.managed-support.613c" + ], + "desc": "Replies already stored when the page loads are hidden and only replies that arrive while the page is open are shown, so a reloaded customer or staff member cannot see the earlier exchange. The live shared-case check exchanges only new replies and is unaffected.", + "file": "client/src/App.tsx", + "edits": [ + { + "find": "import { useEffect, useMemo, useState } from 'react';", + "replace": "import { useEffect, useMemo, useRef, useState } from 'react';" + }, + { + "find": " const [supportReplyRows] = useTable(tables.visibleSupportReplies);", + "replace": " const [liveSupportReplyRows, supportRepliesReady] = useTable(tables.visibleSupportReplies);\n const openedSupportReplies = useRef | null>(null);\n if (openedSupportReplies.current === null && supportRepliesReady) {\n openedSupportReplies.current = new Set(\n liveSupportReplyRows.map((row) => `${row.ticketId}:${row.author}:${row.body}`)\n );\n }\n const supportReplyRows = liveSupportReplyRows.filter(\n (row) => !openedSupportReplies.current?.has(`${row.ticketId}:${row.author}:${row.body}`)\n );" + } + ] + }, + { + "id": "saving-notification-preferences-resets-the-toggles", + "scenario": "tracks/ecommerce/scenarios/progression-notification-preferences.json", + "targets": [ + "ecommerce.progression.notification-preferences.notification-preferences.630c" + ], + "desc": "Saving sends the chosen preferences but resets both toggles to off and stops the form from following the stored row for the rest of the session, so the saved choice cannot be seen until a reload. The reload and cross-account checks read the stored row on a fresh page and are unaffected.", + "file": "client/src/components/ProgressionWorkbench.tsx", + "edits": [ + { + "find": " useEffect(() => {\n setOrderEnabled(preferences?.orderEnabled ?? false);\n setStockEnabled(preferences?.stockEnabled ?? false);\n }, [preferences?.orderEnabled, preferences?.stockEnabled]);", + "replace": " const [preferencesSubmitted, setPreferencesSubmitted] = useState(false);\n useEffect(() => {\n if (preferencesSubmitted) return;\n setOrderEnabled(preferences?.orderEnabled ?? false);\n setStockEnabled(preferences?.stockEnabled ?? false);\n }, [preferences?.orderEnabled, preferences?.stockEnabled, preferencesSubmitted]);" + }, + { + "find": "onClick={() => reducers?.saveNotificationPreferences({ orderEnabled, stockEnabled })}", + "replace": "onClick={() => { reducers?.saveNotificationPreferences({ orderEnabled, stockEnabled }); setPreferencesSubmitted(true); setOrderEnabled(false); setStockEnabled(false); }}" + } + ] + }, + { + "id": "saving-a-staff-role-snaps-the-input-back-to-the-stored-role", + "scenario": "tracks/ecommerce/scenarios/progression-staff-roles.json", + "targets": [ + "ecommerce.progression.staff-roles.staff-roles.621c" + ], + "desc": "Saving a role sends the new role to the server but snaps the visible input back to the role stored before the save for the rest of the session, so the administrator cannot see the assignment take. A reload renders the stored role, so the durability and boundary checks are unaffected.", + "file": "client/src/components/ProgressionWorkbench.tsx", + "edits": [ + { + "find": " ", + "replace": " " + } + ] + }, + { + "id": "fulfilment-queue-is-frozen-at-page-load", + "scenario": "tracks/ecommerce/scenarios/02-fulfilment-live.json", + "targets": [ + "ecommerce.spec.live-state.fulfilment-queue.1a" + ], + "desc": "The fulfilment queue renders the rows delivered with the page's initial subscription and ignores later updates, so an order placed while the queue is open never appears without a reload.", + "file": "client/src/App.tsx", + "edits": [ + { + "find": "import { useEffect, useMemo, useState } from 'react';", + "replace": "import { useEffect, useMemo, useRef, useState } from 'react';" + }, + { + "find": " const [queueRows] = useTable(tables.fulfilmentQueue);", + "replace": " const [liveQueueRows, queueReady] = useTable(tables.fulfilmentQueue);\n const openedQueueRows = useRef(null);\n if (openedQueueRows.current === null && queueReady) openedQueueRows.current = liveQueueRows;\n const queueRows = openedQueueRows.current ?? liveQueueRows;" + } + ] + }, + { + "id": "low-stock-list-is-frozen-at-page-load", + "scenario": "tracks/ecommerce/scenarios/02-low-stock.json", + "targets": [ + "ecommerce.spec.live-state.inventory-dashboard.5a" + ], + "desc": "The low-stock list is computed once from the first complete stock snapshot and never recomputed, so items no longer enter or leave it as stock is restocked or sold. The seeded low item is in that first snapshot, so the static listing check is unaffected.", + "file": "client/src/App.tsx", + "edits": [ + { + "find": "import { useEffect, useMemo, useState } from 'react';", + "replace": "import { useEffect, useMemo, useRef, useState } from 'react';" + }, + { + "find": " const lowStockItems = useMemo(\n () =>\n [...items]\n .filter((i) => (stockByItem.get(i.id) ?? 0) <= LOW_STOCK_THRESHOLD)\n .sort((a, b) => (stockByItem.get(a.id) ?? 0) - (stockByItem.get(b.id) ?? 0)),\n [items, stockByItem]\n );", + "replace": " const liveLowStockItems = useMemo(\n () =>\n [...items]\n .filter((i) => (stockByItem.get(i.id) ?? 0) <= LOW_STOCK_THRESHOLD)\n .sort((a, b) => (stockByItem.get(a.id) ?? 0) - (stockByItem.get(b.id) ?? 0)),\n [items, stockByItem]\n );\n const openedLowStockItems = useRef(null);\n if (openedLowStockItems.current === null && items.length > 0 && stocks.length > 0) {\n openedLowStockItems.current = liveLowStockItems;\n }\n const lowStockItems = openedLowStockItems.current ?? liveLowStockItems;" + } + ] + }, + { + "id": "category-totals-are-frozen-at-page-load", + "scenario": "tracks/ecommerce/scenarios/02-operational-category-totals.json", + "targets": [ + "ecommerce.spec.live-state.sales-dashboard.5b" + ], + "desc": "The category totals render the first non-empty row set received and ignore later updates, so a purchase does not move units or revenue while the dashboard is open. A reload receives the stored totals, so the reload check is unaffected.", + "file": "client/src/App.tsx", + "edits": [ + { + "find": "import { useEffect, useMemo, useState } from 'react';", + "replace": "import { useEffect, useMemo, useRef, useState } from 'react';" + }, + { + "find": " const [categoryTotalRows] = useTable(tables.categoryTotals);", + "replace": " const [liveCategoryTotalRows] = useTable(tables.categoryTotals);\n const openedCategoryTotalRows = useRef(null);\n if (openedCategoryTotalRows.current === null && liveCategoryTotalRows.length > 0) {\n openedCategoryTotalRows.current = liveCategoryTotalRows;\n }\n const categoryTotalRows = openedCategoryTotalRows.current ?? liveCategoryTotalRows;" + } + ] + }, + { + "id": "warehouse-totals-are-frozen-at-page-load", + "scenario": "tracks/ecommerce/scenarios/02-transfer-totals.json", + "targets": [ + "ecommerce.spec.live-state.stock-transfers.2b" + ], + "desc": "The per-warehouse totals are computed once from the first stock snapshot and never recomputed, so a transfer moves neither warehouse figure while the dashboard is open.", + "file": "client/src/App.tsx", + "edits": [ + { + "find": "import { useEffect, useMemo, useState } from 'react';", + "replace": "import { useEffect, useMemo, useRef, useState } from 'react';" + }, + { + "find": " const stockByWarehouse = useMemo(() => {\n const map = new Map();\n for (const row of stocks) {\n map.set(row.warehouseId, (map.get(row.warehouseId) ?? 0) + row.quantity);\n }\n return map;\n }, [stocks]);", + "replace": " const liveStockByWarehouse = useMemo(() => {\n const map = new Map();\n for (const row of stocks) {\n map.set(row.warehouseId, (map.get(row.warehouseId) ?? 0) + row.quantity);\n }\n return map;\n }, [stocks]);\n const openedStockByWarehouse = useRef(null);\n if (openedStockByWarehouse.current === null && liveStockByWarehouse.size > 0) {\n openedStockByWarehouse.current = liveStockByWarehouse;\n }\n const stockByWarehouse = openedStockByWarehouse.current ?? liveStockByWarehouse;" + } + ] + }, + { + "id": "transfer-skips-the-source-holding-check", + "scenario": "tracks/ecommerce/scenarios/02-transfer-overdraw.json", + "targets": [ + "ecommerce.spec.transactional-integrity.stock-transfer-overdraw.2c" + ], + "desc": "The serialized transfer reducer no longer checks that the source warehouse holds the requested quantity, so an overdraw is accepted instead of refused and the source quantity wraps below zero.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": " if (available < quantity) {\n throw new SenderError(`Not enough stock in source warehouse: only ${available} available.`);\n }", + "replace": " // mutant: the source warehouse holding is not checked" + } + ] + }, + { + "id": "credit-checkout-ignores-wallet", + "desc": "A credit checkout pays entirely externally despite available credit.", + "scenario": "tracks/ecommerce/scenarios/progression-store-credit.json", + "targets": [ + "ecommerce.feature.store-credit.store-credit-750.750a" + ], + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": " const creditMinor = useCredit ? Math.min(wallet?.amountMinor ?? 0,totalMinor) : 0;", + "replace": " const creditMinor = 0;" + } + ] + }, + { + "id": "credit-grant-replay-increments-balance", + "desc": "Replaying a grant applies its credit to the wallet again.", + "scenario": "tracks/ecommerce/scenarios/progression-store-credit.json", + "targets": [ + "ecommerce.spec.store-credit.production-752.752a" + ], + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": " if (existing.amountMinor !== amountMinor) throw new SenderError('Reference identifies another grant.');\n return;", + "replace": " if (existing.amountMinor !== amountMinor) throw new SenderError('Reference identifies another grant.');\n const wallet = ctx.db.creditWallet.accountId.find(accountId)!;\n ctx.db.creditWallet.accountId.update({ ...wallet, amountMinor: wallet.amountMinor + amountMinor });\n return;" + } + ] + }, + { + "id": "customer-can-grant-credit", + "desc": "Customer authentication is accepted without staff authorization.", + "scenario": "tracks/ecommerce/scenarios/progression-store-credit.json", + "targets": [ + "ecommerce.spec.store-credit.production-753.753a" + ], + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": " (ctx, { accountId, amountMinor, reference }) => {\n requireStaffOrAdmin(ctx);", + "replace": " (ctx, { accountId, amountMinor, reference }) => {\n requireAccount(ctx);" + } + ] + }, + { + "id": "split-refund-does-not-restore-credit", + "desc": "The refund is recorded but its original wallet credit is not restored.", + "scenario": "tracks/ecommerce/scenarios/progression-split-tender-refunds.json", + "targets": [ + "ecommerce.feature.split-tender-refunds.split-tender-refunds-751.751a" + ], + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": " refundOrderCredit(ctx, order, order.total);", + "replace": " // mutant: omit wallet restoration" + } + ] + }, + { + "id": "split-refund-duplicates-credit", + "desc": "A refund credits the wallet twice while recording one refund.", + "scenario": "tracks/ecommerce/scenarios/progression-split-tender-refunds.json", + "targets": [ + "ecommerce.spec.split-tender-refunds.production-756.756a" + ], + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": "amountMinor: wallet.amountMinor + delta", + "replace": "amountMinor: wallet.amountMinor + delta * 2" + } + ] + }, + { + "id": "subscription-skips-due-purchase", + "desc": "Due deliveries are recorded as skipped although stock is available.", + "scenario": "tracks/ecommerce/scenarios/progression-subscriptions.json", + "targets": [ + "ecommerce.feature.subscriptions.subscriptions-760.760a" + ], + "file": "backend/spacetimedb/src/subscriptions.ts", + "edits": [ + { + "find": " const orderId = purchase(row.accountId, row.itemId, row.quantity, row.price);", + "replace": " const orderId: bigint | null = null;" + } + ] + }, + { + "id": "subscription-allows-foreign-cancellation", + "desc": "A customer can cancel another customer subscription.", + "scenario": "tracks/ecommerce/scenarios/progression-subscriptions.json", + "targets": [ + "ecommerce.spec.subscriptions.production-762.762a" + ], + "file": "backend/spacetimedb/src/subscriptions.ts", + "edits": [ + { + "find": " if (!row || row.accountId !== accountId) throw new SenderError('Subscription access denied.');", + "replace": " if (!row) throw new SenderError('Subscription access denied.');" + } + ] + }, + { + "id": "subscription-pause-is-not-recorded", + "desc": "Pause acknowledges the request but the subscription remains active.", + "scenario": "tracks/ecommerce/scenarios/progression-subscriptions.json", + "targets": [ + "ecommerce.spec.subscriptions.production-763.763a" + ], + "file": "backend/spacetimedb/src/subscriptions.ts", + "edits": [ + { + "find": " ctx.db.purchaseSubscription.id.update({ ...row, status: 'paused', pausedMicros: now });", + "replace": " ctx.db.purchaseSubscription.id.update({ ...row, status: 'active', pausedMicros: now });" + } + ] + }, + { + "id": "credit-checkout-retains-purchased-cart", + "scenario": "tracks/ecommerce/scenarios/progression-store-credit.json", + "targets": [ + "ecommerce.spec.store-credit.production-754.754a" + ], + "desc": "The purchased cart remains available instead of being consumed by checkout.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": " for (const line of lines) ctx.db.cartItem.id.delete(line.id);", + "replace": " // mutant: checked-out lines remain in the cart" + } + ] + }, + { + "id": "reconnection-erases-stored-credit", + "desc": "A new connection erases stored wallet credit; the fresh view after restart must catch the data loss.", + "file": "backend/spacetimedb/src/index.ts", + "scenario": "tracks/ecommerce/scenarios/progression-store-credit.json", + "targets": [ + "ecommerce.spec.store-credit.production-755.755a" + ], + "edits": [ + { + "find": "// --- views ---", + "replace": "export const onConnect = spacetimedb.clientConnected(ctx => { for (const row of ctx.db.creditWallet.iter()) ctx.db.creditWallet.accountId.update({ ...row, amountMinor: 0 }); });\n// --- views ---" + } + ] + }, + { + "id": "reconnection-cancels-pending-subscriptions", + "desc": "A new connection cancels pending subscriptions; restarting and reconnecting must preserve this work.", + "file": "backend/spacetimedb/src/index.ts", + "scenario": "tracks/ecommerce/scenarios/progression-subscriptions.json", + "targets": [ + "ecommerce.spec.subscriptions.production-761.761a" + ], + "edits": [ + { + "find": "// --- views ---", + "replace": "export const onConnect = spacetimedb.clientConnected(ctx => { for (const row of ctx.db.purchaseSubscription.iter()) if (row.status === 'active') ctx.db.purchaseSubscription.id.update({ ...row, status: 'cancelled' }); });\n// --- views ---" + } + ] + }, + { + "id": "bundle-definition-loses-component-quantity", + "scenario": "tracks/ecommerce/scenarios/progression-product-bundles.json", + "targets": [ + "ecommerce.feature.product-bundles.product-bundles.740a" + ], + "desc": "definition loses component quantity", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": "return { ...component, itemId: String(product.id) };", + "replace": "return { ...component, quantity: 1, itemId: String(product.id) };" + } + ] + }, + { + "id": "bundle-catalog-write-allows-customers", + "scenario": "tracks/ecommerce/scenarios/progression-product-bundles.json", + "targets": [ + "ecommerce.spec.bundle-integrity.bundle-743.743a" + ], + "desc": "catalog write allows customers", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": "const actor = requireStaffOrAdmin(ctx);\n if (!actor.isAdmin && ctx.db.staffRole.accountId.find(actor.id)?.role !== 'catalog') {", + "replace": "const actor = requireAccount(ctx);\n if (false) {" + } + ] + }, + { + "id": "bundle-checkout-price-not-snapshot", + "scenario": "tracks/ecommerce/scenarios/progression-bundle-checkout.json", + "targets": [ + "ecommerce.feature.bundle-checkout.bundle-checkout.741a" + ], + "desc": "checkout price not snapshot", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": "bundlePrice: product.price, bundleComponentsJson: definition.componentsJson", + "replace": "bundlePrice: product.price + 1, bundleComponentsJson: definition.componentsJson" + } + ] + }, + { + "id": "bundle-return-loses-original-components", + "scenario": "tracks/ecommerce/scenarios/progression-bundle-returns.json", + "targets": [ + "ecommerce.feature.bundle-returns.bundle-returns.742a" + ], + "desc": "return loses original components", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": "for (const line of bundles) {\n restoreOrderItemStock(ctx, line);", + "replace": "for (const line of bundles) {\n // mutant: original stock is not restored" + } + ] + }, + { + "id": "bundle-return-replay-restocks-again", + "scenario": "tracks/ecommerce/scenarios/progression-bundle-returns.json", + "targets": [ + "ecommerce.spec.bundle-integrity.bundle-742.742b" + ], + "desc": "return replay restocks again", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": ".filter(row => row.isBundle && !row.returned);", + "replace": ".filter(row => row.isBundle);" + } + ] + }, + { + "id": "bundle-return-crosses-account-boundary", + "scenario": "tracks/ecommerce/scenarios/progression-bundle-returns.json", + "targets": [ + "ecommerce.spec.bundle-integrity.bundle-748.748a" + ], + "desc": "return crosses account boundary", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": "if (!order || order.accountId !== account.id || !['shipped', 'delivered'].includes(order.status))", + "replace": "if (!order || !['shipped', 'delivered'].includes(order.status))" + } + ] + }, + { + "id": "bundle-components-can-overdraw", + "scenario": "tracks/ecommerce/scenarios/progression-bundle-checkout.json", + "targets": [ + "ecommerce.spec.bundle-integrity.bundle-744.744a", + "ecommerce.spec.bundle-integrity.bundle-745.745a" + ], + "desc": "components can overdraw", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": "if (!allocations) throw new SenderError('Not enough stock to reserve.');", + "replace": "if (!allocations) { if (bundleId) return; throw new SenderError('Not enough stock to reserve.'); }" + } + ] + }, + { + "id": "bundle-checkout-reuses-reservation", + "scenario": "tracks/ecommerce/scenarios/progression-bundle-checkout.json", + "targets": [ + "ecommerce.spec.bundle-integrity.bundle-747.747a" + ], + "desc": "checkout reuses reservation", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": "for (const row of held) ctx.db.reservation.id.delete(row.id);\n processReorderRules(ctx, p.itemId);", + "replace": "// mutant: reservations survive checkout\n processReorderRules(ctx, p.itemId);" + }, + { + "find": "for (const line of lines) ctx.db.cartItem.id.delete(line.id);", + "replace": "// mutant: cart survives checkout" + } + ] + }, + { + "id": "bundle-expiry-does-not-release-components", + "scenario": "tracks/ecommerce/scenarios/progression-bundle-checkout.json", + "targets": [ + "ecommerce.spec.bundle-integrity.bundle-746.746a" + ], + "desc": "Expired bundle reservations retain their component stock after restart.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": "if (row.expired || row.expiresMicros > now) continue;\n restoreStock(ctx, row.stockItemId || row.itemId, row.warehouseId, row.quantity);", + "replace": "if (row.expired || row.expiresMicros > now) continue;\n if (!row.stockItemId) restoreStock(ctx, row.itemId, row.warehouseId, row.quantity);" + } + ] + }, + { + "id": "return-after-support-refund-is-blocked", + "scenario": "tracks/ecommerce/scenarios/progression-support-return-interaction.json", + "targets": [ + "ecommerce.feature.split-tender-refunds.return-refund-interaction.757a" + ], + "desc": "Reject a valid physical return after a financial refund.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": " if (target.returned) throw new SenderError('Item already returned.');", + "replace": " if (target.returned || order.refundedTotal > 0) throw new SenderError('Item already returned.');" + } + ] + }, + { + "id": "support-refund-after-return-pays-twice", + "scenario": "tracks/ecommerce/scenarios/progression-support-return-interaction.json", + "targets": [ + "ecommerce.feature.split-tender-refunds.return-refund-interaction.757b" + ], + "desc": "Pay the full order again after the physical return already refunded it.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": " const amount = order.total - order.refundedTotal;", + "replace": " const amount = order.total;" + }, + { + "find": "refundedTotal: order.total, status: order.status", + "replace": "refundedTotal: order.refundedTotal + amount, status: order.status" + } + ] + }, + { + "id": "support-history-leaks-to-signed-out-visitors", + "scenario": "tracks/ecommerce/scenarios/progression-support-history.json", + "targets": [ + "ecommerce.spec.access-control.support-history-logout.612d" + ], + "desc": "Disclose support tickets to signed-out visitors while leaving signed-in ownership filtering unchanged.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": ".filter(row => isGuestTicketCreator(sender, row.creatorIdentity.toHexString(), row.accountId) ||", + "replace": ".filter(row => !actor || isGuestTicketCreator(sender, row.creatorIdentity.toHexString(), row.accountId) ||" + } + ] + }, + { + "id": "checkout-crash-integrity", + "scenario": "tracks/ecommerce/scenarios/progression-checkout-crash.json", + "targets": [ + "ecommerce.spec.state-durability.checkout-crash-integrity.910a" + ], + "desc": "A lifecycle callback changes a prepared or cleared cart to quantity two, leaving neither a legal rollback nor a complete checkout.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": "// --- views ---", + "replace": "export const onDisconnect = spacetimedb.clientDisconnected((ctx) => { for (const row of ctx.db.cartItem.iter()) if ([...ctx.db.customerOrder.iter()].some(order => order.accountId === row.accountId)) ctx.db.cartItem.id.update({ ...row, quantity: 2 }); });\n// --- views ---" + } + ] + }, + { + "id": "checkout-crash-durability", + "scenario": "tracks/ecommerce/scenarios/progression-checkout-crash.json", + "targets": [ + "ecommerce.spec.state-durability.checkout-crash-durability.910b" + ], + "desc": "A lifecycle callback corrupts earlier order totals. The unchanged prepared snapshots and acknowledged baseline must expose the damage.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": "// --- views ---", + "replace": "export const onDisconnect = spacetimedb.clientDisconnected((ctx) => { for (const order of ctx.db.customerOrder.iter()) if ([...ctx.db.cartItem.iter()].some(row => row.accountId === order.accountId)) ctx.db.customerOrder.id.update({ ...order, total: 0 }); });\n// --- views ---" + } + ] + }, + { + "id": "review-script-unsafe-render", + "scenario": "tracks/ecommerce/scenarios/progression-review-script.json", + "targets": [ + "ecommerce.progression.review-access-specifications.stored-review-script.9180a" + ], + "desc": "Render stored review text as HTML so it executes in another customer session.", + "file": "client/src/components/ItemDetail.tsx", + "edits": [ + { + "find": "
{r.comment}
", + "replace": "
" + } + ] + }, + { + "id": "review-script-reject-all", + "scenario": "tracks/ecommerce/scenarios/progression-review-script.json", + "targets": [ + "ecommerce.progression.review-access-specifications.stored-review-script.9180a" + ], + "desc": "Reject all nonempty reviews, including the required benign review; absence of script is insufficient.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": "(ctx, { itemId, rating, comment }) => {", + "replace": "(ctx, { itemId, rating, comment }) => {\n if (comment.length > 0) throw new SenderError(\"Review rejected\");" + } + ] + }, + { + "id": "review-owner-reject-all", + "scenario": "tracks/ecommerce/scenarios/progression-review-access.json", + "targets": [ + "ecommerce.progression.review-access-specifications.review-eligibility-direct.618a" + ], + "desc": "Reject the legitimate buyer review as well as unauthorized reviews.", + "file": "backend/spacetimedb/src/index.ts", + "edits": [ + { + "find": "(ctx, { itemId, rating, comment }) => {", + "replace": "(ctx, { itemId, rating, comment }) => {\n if (comment.length > 0) throw new SenderError(\"Reject all reviews\");" + } + ] + }, + { + "id": "password-verification-truncates-utf8", + "scenario": "tracks/ecommerce/scenarios/01-account-password.json", + "targets": [ + "ecommerce.feature.accounts.accounts.1c" + ], + "desc": "Hash and verify only the first 72 UTF-8 bytes, accepting a different password suffix.", + "file": "backend/spacetimedb/src/auth.ts", + "edits": [ + { + "find": "scrypt(password, salt, {", + "replace": "scrypt(new TextEncoder().encode(password).slice(0, 72), salt, {" + } + ] + }, + { + "id": "password-verification-rejects-every-login", + "scenario": "tracks/ecommerce/scenarios/01-account-password.json", + "targets": [ + "ecommerce.feature.accounts.accounts.1c" + ], + "desc": "Refuse even a correct password; refusal alone must not earn credit.", + "file": "backend/spacetimedb/src/auth.ts", + "edits": [ + { + "find": "const valid = !!account && sameHash(digest, account.passwordHash);", + "replace": "const valid = !!account && sameHash(digest, account.passwordHash) && false;" + } + ] + } + ] +} diff --git a/tools/stack-bench/grader/transport-frames.ts b/tools/stack-bench/grader/transport-frames.ts new file mode 100644 index 00000000000..7889eabe4eb --- /dev/null +++ b/tools/stack-bench/grader/transport-frames.ts @@ -0,0 +1,92 @@ +import { brotliDecompressSync, gunzipSync } from 'node:zlib'; +import type { Page } from 'playwright'; +import { inconclusive } from '../src/actions/actor-action-runtime.js'; + +const MAX_RECEIVED_BYTES = 8 * 1024 * 1024; + +// A SpacetimeDB server frame carries a one-byte compression tag ahead of the +// message: 0 none, 1 brotli, 2 gzip, and the SDK compresses by default. The +// message text is inline UTF-8 once decoded, so a substring search finds it +// without the harness knowing the wire format. Any other frame is kept as it +// arrived. +export function transportFrameText(payload: string | Buffer): string { + if (typeof payload === 'string') return payload; + const bytes = Buffer.from(payload); + if (bytes.length > 1) { + try { + if (bytes[0] === 1) return brotliDecompressSync(bytes.subarray(1)).toString('utf8'); + if (bytes[0] === 2) return gunzipSync(bytes.subarray(1)).toString('utf8'); + } catch { /* not a compressed SpacetimeDB frame */ } + } + return bytes.toString('utf8'); +} + +// Bounded evidence must never turn dropped data into a privacy pass. +export class ReceivedTransport { + readonly chunks: string[] = []; + private bytes = 0; + private readonly incompleteCounts = { byteLimit: 0, bodyReadFailures: 0, unsupportedStreams: 0 }; + incomplete = false; + pending = 0; + + constructor(private readonly limit = MAX_RECEIVED_BYTES) {} + + markIncomplete(reason: keyof ReceivedTransport['incompleteCounts']): void { + this.incomplete = true; + this.incompleteCounts[reason]++; + } + + record(payload: string | Buffer): void { + const text = transportFrameText(payload); + if (!text) return; + if (Buffer.byteLength(text) > this.limit) { + this.markIncomplete('byteLimit'); + return; + } + this.chunks.push(text); + this.bytes += Buffer.byteLength(text); + while (this.bytes > this.limit) { + this.markIncomplete('byteLimit'); + this.bytes -= Buffer.byteLength(this.chunks.shift()!); + } + } + + contains(needle: string, requireComplete = true): boolean { + if (this.chunks.some(chunk => chunk.includes(needle))) return true; + if (requireComplete && (this.incomplete || this.pending)) inconclusive('transport-incomplete', { + capture: { ...this.incompleteCounts, pendingBodies: this.pending, retainedBytes: this.bytes }, + }); + return false; + } +} + +export async function captureResponses(page: Page, received: ReceivedTransport): Promise { + page.on('response', async response => { + const type = response.headers()['content-type'] ?? ''; + // Native EventSource messages are captured below without waiting for stream closure. + if (/text\/event-stream/.test(type)) return; + // Include server-rendered data. JavaScript and CSS bundles are not data responses. + if (!/(application\/json|application\/[^;]+\+json|application\/x-ndjson|text\/(plain|html))/.test(type)) return; + if (Number(response.headers()['content-length']) > MAX_RECEIVED_BYTES) { + received.markIncomplete('byteLimit'); + return; + } + received.pending++; + try { received.record(await response.text()); } + catch { received.markIncomplete('bodyReadFailures'); } + finally { received.pending--; } + }); + const session = await page.context().newCDPSession(page); + session.on('Network.eventSourceMessageReceived', event => received.record(event.data)); + session.on('Network.responseReceived', event => { + // Fetch streams have no EventSource events. Absence of an unseen body is not a pass. + if (event.response.mimeType === 'text/event-stream' && event.type !== 'EventSource') { + received.markIncomplete('unsupportedStreams'); + } + }); + await session.send('Network.enable'); + // Keep response bodies available when the app reloads immediately after reading them. + await session.send('Network.configureDurableMessages', { + maxTotalBufferSize: MAX_RECEIVED_BYTES, maxResourceBufferSize: MAX_RECEIVED_BYTES, + }); +} diff --git a/tools/stack-bench/linter/fixtures/agreed.html b/tools/stack-bench/linter/fixtures/agreed.html new file mode 100644 index 00000000000..c462174caf2 --- /dev/null +++ b/tools/stack-bench/linter/fixtures/agreed.html @@ -0,0 +1,4 @@ +agreement fixture + +4 + diff --git a/tools/stack-bench/linter/fixtures/divergent.html b/tools/stack-bench/linter/fixtures/divergent.html new file mode 100644 index 00000000000..5d95d68cd79 --- /dev/null +++ b/tools/stack-bench/linter/fixtures/divergent.html @@ -0,0 +1,12 @@ +divergence fixture + +
+ + + diff --git a/tools/stack-bench/linter/fixtures/mock-chat.html b/tools/stack-bench/linter/fixtures/mock-chat.html new file mode 100644 index 00000000000..2677b6feb48 --- /dev/null +++ b/tools/stack-bench/linter/fixtures/mock-chat.html @@ -0,0 +1,71 @@ + + +Linter fixture — mock chat + + +
+ + +
+ + + + + + diff --git a/tools/stack-bench/linter/fixtures/mock-shop.html b/tools/stack-bench/linter/fixtures/mock-shop.html new file mode 100644 index 00000000000..5034271fdc9 --- /dev/null +++ b/tools/stack-bench/linter/fixtures/mock-shop.html @@ -0,0 +1,297 @@ + +

Mock Shop

+ +
+ + + + + +
+ + + + + +
+ + + + + + + + + + + + + + diff --git a/tools/stack-bench/linter/fixtures/spec-accounts.html b/tools/stack-bench/linter/fixtures/spec-accounts.html new file mode 100644 index 00000000000..ddbb1ad5630 --- /dev/null +++ b/tools/stack-bench/linter/fixtures/spec-accounts.html @@ -0,0 +1,29 @@ + +
+ + + + + +
+ + diff --git a/tools/stack-bench/linter/lint.ts b/tools/stack-bench/linter/lint.ts new file mode 100644 index 00000000000..a352bd43b8c --- /dev/null +++ b/tools/stack-bench/linter/lint.ts @@ -0,0 +1,243 @@ +#!/usr/bin/env node +// Scenario-stage hooks require scenario setup and are not linted here. + +import { chromium } from 'playwright'; +import { attemptBrowserLaunchOptions } from '../container/browser-pipe.js'; +import type { Page } from 'playwright'; +import { readFileSync, readdirSync } from 'node:fs'; +import { join } from 'node:path'; +import { fileURLToPath, pathToFileURL } from 'node:url'; +import { parseArgs as parseNodeArgs } from 'node:util'; +import { loadTrack, DEFAULT_TRACK } from '../src/composition/tracks.js'; +import { emptyArtifactIdentities, writeArtifact } from '../src/evidence/artifacts.js'; +import { stableElementSelector } from '../src/actions/element-selector.js'; + +const CHECK_TIMEOUT = 5000; + +export interface LintHook { + id: string; + element: string; + stage: string; + check: 'visible' | 'attached'; + note: string; + revealedBy?: string; +} + +export interface LintResult { + id: string; + status: 'PASS' | 'FAIL' | 'BLOCKED' | 'SCENARIO'; + detail?: string; +} + +export interface LintArgs { + url?: string; + track: string; + level: number; + json: boolean; + headed: boolean; + out?: string; + label?: string; + parentAttemptId?: string; + credentialAliases?: unknown; + hooks?: string[]; +} + +export interface LintWalkContext { + page: Page; + args: LintArgs; + hooks: LintHook[]; + byStage(stage: string): LintHook[]; + blocked(stage: string): void; + checkHook(page: Page, hook: LintHook, results: LintResult[]): Promise; + results: LintResult[]; + uniq: string; + tid(id: string): string; + CHECK_TIMEOUT: number; +} + +function parseArgs(argv: string[]): LintArgs { + const { values } = parseNodeArgs({ args: argv.slice(2), options: { + url: { type: 'string' }, track: { type: 'string' }, level: { type: 'string' }, + json: { type: 'boolean' }, out: { type: 'string' }, label: { type: 'string' }, + 'parent-attempt-id': { type: 'string' }, 'credential-aliases-json': { type: 'string' }, + hook: { type: 'string', multiple: true }, 'selected-hooks': { type: 'boolean' }, + headed: { type: 'boolean' }, + } }); + const args: LintArgs = { url: values.url, track: values.track ?? DEFAULT_TRACK, + level: values.level === undefined ? 1 : Number(values.level), json: values.json ?? false, + headed: values.headed ?? false, out: values.out, label: values.label, + parentAttemptId: values['parent-attempt-id'], + credentialAliases: values['credential-aliases-json'] === undefined + ? undefined : JSON.parse(values['credential-aliases-json']), + hooks: values.hook ?? (values['selected-hooks'] ? [] : undefined) }; + if (!args.url || !Number.isInteger(args.level) || args.level < 1) { + console.error('Usage: node dist/linter/lint.js --url --level [--json] [--headed]'); + process.exit(2); + } + return args; +} + +export function selectHooks(hooks: LintHook[], selectedIds?: string[]): LintHook[] { + if (selectedIds === undefined) return hooks; + const remaining = new Set(selectedIds); + const selected = hooks.filter(hook => remaining.delete(hook.id)); + const unknown: LintHook[] = [...remaining].sort().map(id => ({ + id, + element: `the selected application control ${id}`, + stage: 'scenario', + check: 'visible', + note: 'checked by the selected feature suite', + })); + return [...selected, ...unknown]; +} + +export function loadHooks(level: number, track: { contracts: string }, selectedIds?: string[]): LintHook[] { + const CONTRACTS_DIR = track.contracts; + const files = readdirSync(CONTRACTS_DIR).filter(f => /^\d+-[a-z-]+\.json$/.test(f)).sort(); + const hooks = []; + for (const f of files) { + const contract = JSON.parse(readFileSync(join(CONTRACTS_DIR, f), 'utf8')) as { + level: number; hooks: LintHook[]; + }; + if (contract.level <= level) hooks.push(...contract.hooks); + } + if (hooks.length === 0 && selectedIds === undefined) { + console.error(`No contracts found for level ${level} in ${CONTRACTS_DIR}`); + process.exit(2); + } + return selectHooks(hooks, selectedIds); +} + +const tid = stableElementSelector; +const uniq = Date.now().toString(36).slice(-5); + +async function checkHook(page: Page, hook: LintHook, results: LintResult[]): Promise { + const loc = page.locator(tid(hook.id)).first(); + try { + if (hook.revealedBy && !(await loc.count())) { + await page.locator(tid(hook.revealedBy)).first().click({ timeout: CHECK_TIMEOUT }); + } + await loc.waitFor({ + state: hook.check === 'visible' ? 'visible' : 'attached', + timeout: CHECK_TIMEOUT, + }); + results.push({ id: hook.id, status: 'PASS' }); + return true; + } catch { + results.push({ + id: hook.id, + status: 'FAIL', + detail: `no element matching ${tid(hook.id)} became ${hook.check} during contract stage ${JSON.stringify(hook.stage)}` + + (hook.revealedBy ? ` (after clicking ${tid(hook.revealedBy)})` : '') + + ` — expected: ${hook.element}`, + }); + return false; + } +} + +export function completeUnvisitedHooks(hooks: LintHook[], results: LintResult[]): LintResult[] { + const visited = new Set(results.map(result => result.id)); + for (const hook of hooks) { + if (visited.has(hook.id)) continue; + results.push(hook.stage === 'scenario' + ? { id: hook.id, status: 'SCENARIO', detail: hook.note } + : { id: hook.id, status: 'BLOCKED', + detail: `the core flow did not visit contract stage ${JSON.stringify(hook.stage)}` }); + } + return results; +} + +export function completeAbortedHooks(hooks: LintHook[], results: LintResult[], error: unknown): LintResult[] { + const visited = new Set(results.map(result => result.id)); + const detail = String(error instanceof Error ? error.message : error ?? 'unknown error') + .split(/\r?\n/).map(line => line.trim()).filter(Boolean).slice(0, 6).join(' ').slice(0, 800); + results.push({ id: 'core-flow', status: 'FAIL', detail: `core flow aborted: ${detail}` }); + for (const hook of hooks) { + if (visited.has(hook.id)) continue; + if (hook.stage === 'scenario') { + results.push({ id: hook.id, status: 'SCENARIO', detail: hook.note }); + } else { + results.push({ id: hook.id, status: 'BLOCKED', detail: 'core flow aborted' }); + } + } + return results; +} + +async function run() { + const args = parseArgs(process.argv); + const track = loadTrack(args.track); + const hooks = loadHooks(args.level, track, args.hooks); + const byStage = (stage: string): LintHook[] => hooks.filter(h => h.stage === stage); + const results: LintResult[] = []; + const blocked = (stage: string): void => { + for (const h of hooks.filter(x => x.stage === stage)) { + results.push({ id: h.id, status: 'BLOCKED', detail: 'earlier core flow step failed' }); + } + }; + + if (hooks.length) { + const browser = await chromium.launch({ headless: !args.headed, ...attemptBrowserLaunchOptions() }); + const page = await browser.newContext().then(c => c.newPage()); + page.setDefaultTimeout(CHECK_TIMEOUT); + + try { + // The core flow is the one part of linting that is entirely + // application-specific, so each track brings its own. + const { walk } = await import(pathToFileURL(track.walk).href) as { + walk(context: LintWalkContext): Promise; + }; + await walk({ page, args, hooks, byStage, blocked, checkHook, results, uniq, tid, CHECK_TIMEOUT }); + // Every lintable hook must record explicit evidence. + completeUnvisitedHooks(hooks, results); + } catch (err: unknown) { + console.error(`Core flow aborted: ${err instanceof Error ? err.message : String(err)}`); + completeAbortedHooks(hooks, results, err); + } finally { + await browser.close(); + } + } + + const failures = results.filter(r => r.status === 'FAIL' || r.status === 'BLOCKED'); + const report = { + label: args.label ?? null, + url: args.url, + level: args.level, + selectedHooks: args.hooks === undefined ? null : [...new Set(args.hooks)].sort(), + pass: failures.length === 0, + counts: { + lintable: results.filter(r => r.status !== 'SCENARIO').length, + pass: results.filter(r => r.status === 'PASS').length, + fail: results.filter(r => r.status === 'FAIL').length, + blocked: results.filter(r => r.status === 'BLOCKED').length, + scenario: results.filter(r => r.status === 'SCENARIO').length, + }, + results, + }; + if (args.out) { + const id = `${args.parentAttemptId ?? args.label ?? 'lint'}-contract-lint`; + writeArtifact(args.out, { + kind: 'contract_lint', id, + attempt: { id, parentId: args.parentAttemptId ?? null }, + identities: emptyArtifactIdentities(), + payload: report, + }); + if (!args.json) console.log(`\nLint report written to ${args.out}`); + } + if (args.json) { + console.log(JSON.stringify(report, null, 2)); + } else { + for (const r of results) { + console.log(`${r.status.padEnd(9)} ${r.id}${r.detail ? ` — ${r.detail}` : ''}`); + } + console.log(failures.length === 0 + ? report.counts.pass > 0 + ? `\nAPPLICATION CONTRACT PASS (${report.counts.pass} interfaces)` + : report.counts.scenario > 0 + ? `\nAPPLICATION CONTRACT DEFERRED (${report.counts.scenario} interfaces checked during feature grading)` + : '\nNO STANDALONE INTERFACES SELECTED' + : `\nAPPLICATION CONTRACT FAIL (${failures.length} interfaces missing or blocked)`); + } + process.exit(failures.length === 0 ? 0 : 1); +} + +if (process.argv[1] && fileURLToPath(import.meta.url) === process.argv[1]) run(); diff --git a/tools/stack-bench/package-lock.json b/tools/stack-bench/package-lock.json new file mode 100644 index 00000000000..430532137f5 --- /dev/null +++ b/tools/stack-bench/package-lock.json @@ -0,0 +1,136 @@ +{ + "name": "@spacetimedb/stack-bench", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@spacetimedb/stack-bench", + "dependencies": { + "eventsource-parser": "3.1.1", + "playwright": "1.62.1", + "semver": "7.7.4", + "zod": "4.5.4" + }, + "devDependencies": { + "@types/node": "22.15.30", + "@types/semver": "7.8.0", + "typescript": "5.6.3" + }, + "engines": { + "node": ">=22" + } + }, + "node_modules/@types/node": { + "version": "22.15.30", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.30.tgz", + "integrity": "sha512-6Q7lr06bEHdlfplU6YRbgG1SFBdlsfNC4/lX+SkhiTs0cpJkOElmWls8PxDFv4yY/xKb8Y6SO0OmSX4wgqTZbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/semver": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.8.0.tgz", + "integrity": "sha512-1mAINjtQCXXeLkJ9ehXkwOcBpqtLxiVtKhpUf83DdRNdQKV0iXZpaHYqRr7nj+wvxuJzoAmAwXI+sCNMv1CzLQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/eventsource-parser": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.1.1.tgz", + "integrity": "sha512-EKN1vKAMcZ8MlYMpaNuxN6R9yakzH6uajHcHVTqWJzvu5pWw9DyhbP35HH8MVBQ+dZjAfDxk+A8NiR9KWaXiyQ==", + "license": "MIT", + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/playwright": { + "version": "1.62.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.62.1.tgz", + "integrity": "sha512-0M+L3LAD8/nm554LOla9Ayx0j0tmFZ0FBcoQ7F1VuVHpM/XpiC8RcDzBQB8W5+hA8L22THxELzeF+2WcUzvcLg==", + "license": "Apache-2.0", + "dependencies": { + "playwright-core": "1.62.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=20" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.62.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.62.1.tgz", + "integrity": "sha512-wPYSwEBJY9GHraISXqyqtx0na0LpO3XEX7jNDhntbex7tzUS7kLnZsOlFruFJB4Hi/rhDMjXGqHewDZ68nYZVw==", + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/typescript": { + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", + "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/zod": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.5.4.tgz", + "integrity": "sha512-sC95tT5iHHH9gtpj6A81kh+NEaRAUFN+qlUPDUbRfOMvNf5QCBqsb3WgvnpVtK5Y+4UfA6KqufotuTvMGiTlsA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + } + } +} diff --git a/tools/stack-bench/package.json b/tools/stack-bench/package.json new file mode 100644 index 00000000000..3030d3f5c7f --- /dev/null +++ b/tools/stack-bench/package.json @@ -0,0 +1,85 @@ +{ + "name": "@spacetimedb/stack-bench", + "private": true, + "type": "module", + "engines": { + "node": ">=22" + }, + "scripts": { + "build": "npm run clean && tsc -p tsconfig.build.json && node dist/scripts/copy-dashboard-assets.js", + "clean": "node --eval \"require('node:fs').rmSync('dist', { recursive: true, force: true })\"", + "lint": "eslint appliance commands container dashboard grader linter scripts src tests", + "typecheck": "tsc -p tsconfig.json --noEmit", + "bootstrap:browsers": "playwright install chromium", + "prebench": "npm run build --silent", + "bench": "node dist/commands/bench.js", + "prepreflight": "npm run build", + "preflight": "node dist/commands/preflight.js", + "prerecover": "npm run build", + "recover": "node dist/commands/recovery.js recover", + "prerelease:bundle": "npm run build --silent", + "release:bundle": "node dist/src/releases/release-bundle.js", + "release:source": "npm run build --silent && node dist/src/releases/release-source.js --json", + "preverify:release": "npm run build --silent", + "verify:release": "node dist/src/releases/release-manifest.js verify", + "precheck:scenarios": "npm run build --silent", + "check:scenarios": "node dist/commands/check-scenarios.js --track chat && node dist/commands/check-scenarios.js --track ecommerce --recipe sequential-l1.json && node dist/commands/check-scenarios.js --track ecommerce --recipe sequential-l2.json && node dist/commands/check-scenarios.js --track ecommerce --recipe sequential-l3.json && node dist/commands/check-scenarios.js --track ecommerce --recipe progression-catalog.json", + "precheck:mutations": "npm run build", + "check:mutations": "node dist/commands/check-mutations.js", + "precheck:definition-snapshots": "npm run build --silent", + "check:definition-snapshots": "node dist/commands/definition-snapshots.js", + "precheck:composition": "npm run build --silent", + "check:composition": "node dist/commands/check-composition.js", + "precheck:prompts": "npm run build --silent", + "check:prompts": "node --test dist/tests/dependency-neutral-prompt.contract.js", + "precheck:calibration": "npm run build --silent", + "check:calibration": "node dist/commands/check-calibration.js", + "precheck:references": "npm run build --silent", + "check:references": "node dist/src/references/reference-fixtures.js", + "pregraph": "npm run build", + "graph": "node dist/commands/progression-graph.js tracks/ecommerce/progression/ecommerce.json", + "pack": "npm run build --silent && node dist/commands/composition-cli.js pack", + "recipe": "npm run build --silent && node dist/commands/composition-cli.js recipe", + "precampaign": "npm run build --silent", + "campaign": "node dist/commands/campaign-cli.js", + "predashboard": "npm run build --silent", + "dashboard": "node dist/dashboard/dashboard-server.js", + "prerepair": "npm run build", + "repair": "node dist/commands/repair-cli.js", + "pretest": "npm run build --silent", + "test": "node --test --test-concurrency=4 dist/tests/*.test.js", + "pretest:dashboard": "npm run build --silent", + "test:dashboard": "node --test dist/tests/dashboard/*.test.js", + "pretest:all": "npm run build --silent", + "test:all": "node --test --test-concurrency=4 dist/tests/*.test.js dist/tests/dashboard/*.test.js dist/tests/*.contract.js", + "pretest:contracts": "npm run build --silent", + "test:contracts": "node --test --test-concurrency=4 dist/tests/*.contract.js", + "pretest:mutation-definitions": "npm run build --silent", + "test:mutation-definitions": "node --test --test-concurrency=4 dist/tests/*.mutation.js", + "pretest:integration": "npm run build --silent", + "test:integration": "node --test --test-concurrency=1 dist/tests/*.integration.js", + "pretest:container": "npm run build --silent", + "test:container": "node dist/commands/container-smoke.js", + "pretest:references": "npm run build --silent", + "test:references": "node dist/src/references/reference-build.js", + "prequalify:reference": "npm run build --silent", + "qualify:reference": "node dist/src/references/reference-live.js", + "pretest:faults": "npm run build --silent", + "test:faults": "node dist/commands/fault-injection.js", + "pretest:loop": "npm run build", + "test:loop": "node dist/commands/test-loop.js", + "pretest:null": "npm run build --silent", + "test:null": "node dist/commands/null-control.js" + }, + "dependencies": { + "eventsource-parser": "3.1.1", + "playwright": "1.62.1", + "semver": "7.7.4", + "zod": "4.5.4" + }, + "devDependencies": { + "@types/node": "22.15.30", + "@types/semver": "7.8.0", + "typescript": "5.6.3" + } +} diff --git a/tools/stack-bench/qualification-evidence/ecommerce-l3-43d01f644/mongodb-mutation.json b/tools/stack-bench/qualification-evidence/ecommerce-l3-43d01f644/mongodb-mutation.json new file mode 100644 index 00000000000..43f9b7269ca --- /dev/null +++ b/tools/stack-bench/qualification-evidence/ecommerce-l3-43d01f644/mongodb-mutation.json @@ -0,0 +1,946 @@ +{ + "artifactSchemaVersion": 2, + "kind": "reference_qualification", + "id": "reference-live-mongodb-20260916171514-31", + "attempt": { + "id": "reference-live-mongodb-20260916171514-31", + "parentId": null + }, + "timestamps": { + "startedAt": "2026-09-16T17:15:14.926Z", + "completedAt": "2026-09-16T18:02:51.513Z" + }, + "identities": { + "engine": { + "id": "stack-bench", + "sha256": "31ffc8e48b22c397d10aa5ca2b6bc0680e9ae20fd8903bccc4d7db406a1478de" + }, + "recipe": { + "id": "ecommerce.progression-catalog", + "sha256": "11d743dd95a4671bdbb71c10f75b8405671f20a32c5312c9832c8ff9481e7ed5" + }, + "fixture": { + "id": "ecommerce-reference-mongodb", + "sha256": "5871985671a9aba778c29954b7b5eb04e45030332e1c809767594bf8ac6c6b11" + }, + "calibration": { + "id": "ecommerce.dependency-l3-calibration", + "sha256": "578942627b3d6827609fb623361e1a672b4a602b65e0f1c501048b346438e954" + }, + "experiment": null, + "agentAdapter": null, + "stackAdapter": { + "id": "mongodb", + "sha256": null + }, + "packs": [] + }, + "payload": { + "fixture": "ecommerce-reference-mongodb", + "fixtureSha256": "5871985671a9aba778c29954b7b5eb04e45030332e1c809767594bf8ac6c6b11", + "requiredRepetitions": 1, + "isolation": "docker", + "runner": { + "schemaVersion": 1, + "mode": "appliance", + "platform": "linux", + "architecture": "x64", + "hostname": "docker-desktop", + "dockerEngineVersion": "29.6.2", + "dockerOs": "linux", + "dockerArchitecture": "x86_64", + "kernelVersion": "6.6.87.2-microsoft-standard-WSL2", + "cpuCount": 32, + "memoryBytes": 49232846848, + "containersRunning": 12, + "packageRegistry": "http://127.0.0.1:4873/" + }, + "qualificationScope": { + "checksSha256": "adc107253c217dc57e6b0648b083b5762f1358871f2764baad8cacfd3083eb10", + "executableSha256": "e88b41e4ece5607d0ab8175a1bdcbc808323ba00dc3908d0626f51d5888a3d8f", + "kind": "mutation", + "mutationSha256": "a85c8853948ca5658df57176309944bc8dbea8137e150325aadc2de8f9b2e4a3", + "recipe": { + "contentSha256": "11d743dd95a4671bdbb71c10f75b8405671f20a32c5312c9832c8ff9481e7ed5", + "id": "ecommerce.progression-catalog" + }, + "schemaVersion": 3, + "stack": { + "id": "mongodb", + "reference": { + "id": "ecommerce-reference-mongodb", + "sourceSha256": "5871985671a9aba778c29954b7b5eb04e45030332e1c809767594bf8ac6c6b11" + }, + "version": "1.5.0" + }, + "sha256": "a320ef3445e2d89713d2c4df560be5e35c22ef4bed225ccfa33c62ba47489fed" + }, + "mutationControl": true, + "runs": [ + { + "repetition": 1, + "output": "ecommerce-l3-11d743dd95a4-mongodb-mutation.runs/r1-workers", + "durationMs": 2856369, + "processError": null, + "harnessSha256Before": "7aa0044000ff319fd5c8b95575d9636a8835ded1afea277d16c7871dd30eadf8", + "harnessSha256After": "7aa0044000ff319fd5c8b95575d9636a8835ded1afea277d16c7871dd30eadf8", + "ok": true, + "failures": [], + "runId": "reference-live-mongodb-20260916171514-31", + "score": "180/180", + "imageId": "sha256:32ff9a9e519ba9d1af2fe72f24622caa8ca7a9f2baf2338c6b1e0435e6ac5455", + "criteria": 111, + "zeroPointCriteria": 0, + "fingerprint": "01676f87359c0bfc4b294128f48746ef655e9e4b61734439a2ea4b95dc34a605", + "outcome": "passed", + "packRuntime": { + "schemaVersion": 1, + "metric": "pack-check-wall-clock-sum-v1", + "packs": [ + { + "id": "ecommerce.feature.accounts", + "checkCount": 4, + "setupRuntimeMs": 1283, + "criterionRuntimeMs": 15198, + "measuredRuntimeMs": 16481, + "budget": { + "status": "bounded", + "maxRuntimeMs": 18000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.cart", + "checkCount": 1, + "setupRuntimeMs": 664, + "criterionRuntimeMs": 6082, + "measuredRuntimeMs": 6746, + "budget": { + "status": "bounded", + "maxRuntimeMs": 42000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.catalog-discovery", + "checkCount": 2, + "setupRuntimeMs": 0, + "criterionRuntimeMs": 1886, + "measuredRuntimeMs": 1886, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.catalog-items", + "checkCount": 1, + "setupRuntimeMs": 0, + "criterionRuntimeMs": 261, + "measuredRuntimeMs": 261, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.checkout", + "checkCount": 1, + "setupRuntimeMs": 664, + "criterionRuntimeMs": 10856, + "measuredRuntimeMs": 11520, + "budget": { + "status": "bounded", + "maxRuntimeMs": 42000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.purchasing", + "checkCount": 1, + "setupRuntimeMs": 350, + "criterionRuntimeMs": 1181, + "measuredRuntimeMs": 1531, + "budget": { + "status": "bounded", + "maxRuntimeMs": 24000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.reviews", + "checkCount": 1, + "setupRuntimeMs": 21517, + "criterionRuntimeMs": 302, + "measuredRuntimeMs": 21819, + "budget": { + "status": "bounded", + "maxRuntimeMs": 22000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.warehouse-admin", + "checkCount": 2, + "setupRuntimeMs": 1707, + "criterionRuntimeMs": 4360, + "measuredRuntimeMs": 6067, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.inventory-dashboard", + "checkCount": 1, + "setupRuntimeMs": 4396, + "criterionRuntimeMs": 8, + "measuredRuntimeMs": 4404, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.order-cancellation-features", + "checkCount": 2, + "setupRuntimeMs": 1150, + "criterionRuntimeMs": 16379, + "measuredRuntimeMs": 17529, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.recommendations", + "checkCount": 1, + "setupRuntimeMs": 316, + "criterionRuntimeMs": 5174, + "measuredRuntimeMs": 5490, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.sales-dashboard", + "checkCount": 2, + "setupRuntimeMs": 2240, + "criterionRuntimeMs": 5072, + "measuredRuntimeMs": 7312, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.stock-transfers-features", + "checkCount": 1, + "setupRuntimeMs": 582, + "criterionRuntimeMs": 2840, + "measuredRuntimeMs": 3422, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.deferred-access-specifications", + "checkCount": 1, + "setupRuntimeMs": 21136, + "criterionRuntimeMs": 4269, + "measuredRuntimeMs": 25405, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.deferred-durability-specifications", + "checkCount": 1, + "setupRuntimeMs": 128951, + "criterionRuntimeMs": 39300, + "measuredRuntimeMs": 168251, + "budget": { + "status": "bounded", + "maxRuntimeMs": 720000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.deferred-integrity-specifications", + "checkCount": 1, + "setupRuntimeMs": 44688, + "criterionRuntimeMs": 39618, + "measuredRuntimeMs": 84306, + "budget": { + "status": "bounded", + "maxRuntimeMs": 400000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.scheduled-restocks-features", + "checkCount": 3, + "setupRuntimeMs": 61680, + "criterionRuntimeMs": 69330, + "measuredRuntimeMs": 131010, + "budget": { + "status": "bounded", + "maxRuntimeMs": 150000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.server-time-specifications", + "checkCount": 1, + "setupRuntimeMs": 28389, + "criterionRuntimeMs": 112939, + "measuredRuntimeMs": 141328, + "budget": { + "status": "bounded", + "maxRuntimeMs": 300000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.cancellation-accounting-specifications", + "checkCount": 1, + "setupRuntimeMs": 726, + "criterionRuntimeMs": 10936, + "measuredRuntimeMs": 11662, + "budget": { + "status": "bounded", + "maxRuntimeMs": 24000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.catalog-management", + "checkCount": 2, + "setupRuntimeMs": 3442, + "criterionRuntimeMs": 32, + "measuredRuntimeMs": 3474, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.customer-profile", + "checkCount": 1, + "setupRuntimeMs": 509, + "criterionRuntimeMs": 5072, + "measuredRuntimeMs": 5581, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.faceted-search", + "checkCount": 2, + "setupRuntimeMs": 43525, + "criterionRuntimeMs": 25591, + "measuredRuntimeMs": 69116, + "budget": { + "status": "bounded", + "maxRuntimeMs": 141000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.fulfilment-queue", + "checkCount": 2, + "setupRuntimeMs": 1366, + "criterionRuntimeMs": 27315, + "measuredRuntimeMs": 28681, + "budget": { + "status": "bounded", + "maxRuntimeMs": 76000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.inventory-conservation-specifications", + "checkCount": 5, + "setupRuntimeMs": 2534, + "criterionRuntimeMs": 64243, + "measuredRuntimeMs": 66777, + "budget": { + "status": "bounded", + "maxRuntimeMs": 138000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.managed-support", + "checkCount": 1, + "setupRuntimeMs": 1152, + "criterionRuntimeMs": 6142, + "measuredRuntimeMs": 7294, + "budget": { + "status": "bounded", + "maxRuntimeMs": 55000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.notification-preferences", + "checkCount": 1, + "setupRuntimeMs": 809, + "criterionRuntimeMs": 5110, + "measuredRuntimeMs": 5919, + "budget": { + "status": "bounded", + "maxRuntimeMs": 40000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.operations-access-specifications", + "checkCount": 3, + "setupRuntimeMs": 10118, + "criterionRuntimeMs": 38409, + "measuredRuntimeMs": 48527, + "budget": { + "status": "bounded", + "maxRuntimeMs": 98000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.promotion-rules", + "checkCount": 1, + "setupRuntimeMs": 657, + "criterionRuntimeMs": 457, + "measuredRuntimeMs": 1114, + "budget": { + "status": "bounded", + "maxRuntimeMs": 45000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.review-access-specifications", + "checkCount": 1, + "setupRuntimeMs": 23782, + "criterionRuntimeMs": 6734, + "measuredRuntimeMs": 30516, + "budget": { + "status": "bounded", + "maxRuntimeMs": 62000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.staff-access", + "checkCount": 1, + "setupRuntimeMs": 0, + "criterionRuntimeMs": 748, + "measuredRuntimeMs": 748, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.staff-roles", + "checkCount": 1, + "setupRuntimeMs": 624, + "criterionRuntimeMs": 74, + "measuredRuntimeMs": 698, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.stock-alerts", + "checkCount": 1, + "setupRuntimeMs": 5102, + "criterionRuntimeMs": 11458, + "measuredRuntimeMs": 16560, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.support-history", + "checkCount": 1, + "setupRuntimeMs": 1306, + "criterionRuntimeMs": 1310, + "measuredRuntimeMs": 2616, + "budget": { + "status": "bounded", + "maxRuntimeMs": 50000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.support-intake", + "checkCount": 1, + "setupRuntimeMs": 0, + "criterionRuntimeMs": 507, + "measuredRuntimeMs": 507, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.support-triage", + "checkCount": 3, + "setupRuntimeMs": 1063, + "criterionRuntimeMs": 10086, + "measuredRuntimeMs": 11149, + "budget": { + "status": "bounded", + "maxRuntimeMs": 45000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.access-control", + "checkCount": 21, + "setupRuntimeMs": 32179, + "criterionRuntimeMs": 220610, + "measuredRuntimeMs": 252789, + "budget": { + "status": "bounded", + "maxRuntimeMs": 464000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.concurrency-safety", + "checkCount": 6, + "setupRuntimeMs": 27142, + "criterionRuntimeMs": 48985, + "measuredRuntimeMs": 76127, + "budget": { + "status": "bounded", + "maxRuntimeMs": 125000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.external-data-sync", + "checkCount": 3, + "setupRuntimeMs": 636, + "criterionRuntimeMs": 29460, + "measuredRuntimeMs": 30096, + "budget": { + "status": "bounded", + "maxRuntimeMs": 105000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.live-state", + "checkCount": 11, + "setupRuntimeMs": 81184, + "criterionRuntimeMs": 9527, + "measuredRuntimeMs": 90711, + "budget": { + "status": "bounded", + "maxRuntimeMs": 184000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.search-ordering", + "checkCount": 1, + "setupRuntimeMs": 21728, + "criterionRuntimeMs": 5183, + "measuredRuntimeMs": 26911, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.state-durability", + "checkCount": 8, + "setupRuntimeMs": 5795, + "criterionRuntimeMs": 74795, + "measuredRuntimeMs": 80590, + "budget": { + "status": "bounded", + "maxRuntimeMs": 408000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.transactional-integrity", + "checkCount": 6, + "setupRuntimeMs": 45804, + "criterionRuntimeMs": 39676, + "measuredRuntimeMs": 85480, + "budget": { + "status": "bounded", + "maxRuntimeMs": 100000 + }, + "exceeded": false + } + ] + }, + "mutations": { + "caught": 108, + "total": 108 + }, + "baselineDurationMs": 2099670, + "baselineOutput": "ecommerce-l3-11d743dd95a4-mongodb-mutation.runs/r1", + "baselineHarnessSha256Before": "7aa0044000ff319fd5c8b95575d9636a8835ded1afea277d16c7871dd30eadf8", + "baselineHarnessSha256After": "7aa0044000ff319fd5c8b95575d9636a8835ded1afea277d16c7871dd30eadf8", + "workers": [ + { + "index": 0, + "runIndex": 0, + "artifact": "ecommerce-l3-11d743dd95a4-mongodb-mutation.runs/r1-workers/w1.json", + "mutationIds": [ + "staff-admin-access-survives-role-removal", + "signed-out-visitor-purchase-is-accepted", + "warehouse-view-omits-one-location", + "purchased-review-ui-does-not-submit", + "cancelled-order-remains-in-revenue-feature", + "recommendations-ignore-pending-purchases", + "staff-can-see-admin-navigation", + "due-restock-does-not-change-stock", + "active-search-uses-purchase-ranking", + "staff-signin-loses-staff-role", + "support-history-is-lost-on-server-restart", + "checkout-claim-is-not-atomic", + "initial-dashboard-load-omits-low-stock", + "live-admin-updates-keep-stale-category-totals" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-11d743dd95a4-mongodb-mutation.runs/r1-workers/w1.stdout.log", + "stderr": "ecommerce-l3-11d743dd95a4-mongodb-mutation.runs/r1-workers/w1.stderr.log" + } + }, + { + "index": 1, + "runIndex": 1, + "artifact": "ecommerce-l3-11d743dd95a4-mongodb-mutation.runs/r1-workers/w2.json", + "mutationIds": [ + "shipping-counts-sale-twice", + "espresso-stock-row-ignores-live-updates", + "unauthenticated-purchase-defaults-to-admin", + "external-stock-polling-disabled", + "cancelled-order-remains-in-revenue-invariant", + "purchases-do-not-affect-best-sellers", + "staff-can-use-direct-restock", + "cancelled-restock-remains-pending", + "pagination-repeats-first-page", + "customer-signin-gains-staff-role", + "support-history-is-not-owner-scoped", + "last-unit-allows-negative-stock", + "category-totals-skip-the-newest-order", + "overdraw-transfer-is-accepted" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-11d743dd95a4-mongodb-mutation.runs/r1-workers/w2.stdout.log", + "stderr": "ecommerce-l3-11d743dd95a4-mongodb-mutation.runs/r1-workers/w2.stderr.log" + } + }, + { + "index": 2, + "runIndex": 2, + "artifact": "ecommerce-l3-11d743dd95a4-mongodb-mutation.runs/r1-workers/w3.json", + "mutationIds": [ + "signup-does-not-expose-created-account", + "purchase-order-uses-zero-price", + "direct-purchase-total-ignores-store-price", + "server-restart-disables-catalog-recovery", + "operator-authorization-allows-customer-transfer", + "queue-warehouse-reports-west", + "restock-adds-the-wrong-quantity", + "server-time-restock-never-completes", + "managed-support-live-refresh-keeps-stale-tickets", + "role-assignment-drops-role", + "support-intake-returns-no-reference", + "purchase-read-write-loses-concurrent-stock", + "profile-summary-frozen-at-open", + "transfer-totals-omit-destination-credit-live" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-11d743dd95a4-mongodb-mutation.runs/r1-workers/w3.stdout.log", + "stderr": "ecommerce-l3-11d743dd95a4-mongodb-mutation.runs/r1-workers/w3.stderr.log" + } + }, + { + "index": 3, + "runIndex": 3, + "artifact": "ecommerce-l3-11d743dd95a4-mongodb-mutation.runs/r1-workers/w4.json", + "mutationIds": [ + "duplicate-signup-reports-success", + "reload-hydrates-an-empty-cart", + "cart-hydration-loses-account-state", + "reconnect-generation-ignores-current-catalog", + "customer-can-ship-order-direct-1-1", + "cart-repeat-does-not-increment", + "transfer-creates-stock-during-race", + "catalog-product-name-is-not-published", + "managed-support-allows-another-customer", + "staff-role-write-precedes-denial", + "support-triage-discards-updates", + "purchase-does-not-reduce-warehouse-stock", + "support-replies-present-at-open-are-hidden", + "support-history-leaks-to-signed-out-visitors" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-11d743dd95a4-mongodb-mutation.runs/r1-workers/w4.stdout.log", + "stderr": "ecommerce-l3-11d743dd95a4-mongodb-mutation.runs/r1-workers/w4.stderr.log" + } + }, + { + "index": 4, + "runIndex": 4, + "artifact": "ecommerce-l3-11d743dd95a4-mongodb-mutation.runs/r1-workers/w5.json", + "mutationIds": [ + "signin-skips-password-verification", + "shared-cart-live-events-ignored", + "reconnect-hydration-loses-account-state", + "open-review-list-ignores-live-update", + "customer-can-cancel-foreign-order-1-1", + "checkout-leaves-cart-claimed", + "customer-can-cancel-scheduled-restock", + "catalog-variants-are-discarded", + "notification-preference-is-not-saved", + "staff-can-assign-roles", + "cart-add-uses-another-account-cart", + "restock-does-not-increase-stock", + "notification-toggle-frozen-at-open" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-11d743dd95a4-mongodb-mutation.runs/r1-workers/w5.stdout.log", + "stderr": "ecommerce-l3-11d743dd95a4-mongodb-mutation.runs/r1-workers/w5.stderr.log" + } + }, + { + "index": 5, + "runIndex": 5, + "artifact": "ecommerce-l3-11d743dd95a4-mongodb-mutation.runs/r1-workers/w6.json", + "mutationIds": [ + "signout-keeps-current-account", + "review-comment-is-not-persisted", + "order-history-is-not-owner-scoped", + "cancel-does-not-restore-stock-feature", + "ship-acknowledges-without-changing-status", + "catalog-initial-ranking-is-reversed", + "scheduled-restock-never-becomes-due-after-restart", + "profile-data-is-lost-on-server-restart", + "notification-preference-is-not-owner-scoped", + "stock-alert-delivery-is-suppressed", + "negative-cart-quantity-is-accepted", + "direct-review-access-is-not-checked", + "role-editor-snaps-back-to-stored-role" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-11d743dd95a4-mongodb-mutation.runs/r1-workers/w6.stdout.log", + "stderr": "ecommerce-l3-11d743dd95a4-mongodb-mutation.runs/r1-workers/w6.stderr.log" + } + }, + { + "index": 6, + "runIndex": 6, + "artifact": "ecommerce-l3-11d743dd95a4-mongodb-mutation.runs/r1-workers/w7.json", + "mutationIds": [ + "session-token-not-persisted", + "repeat-review-uses-a-new-owner-key", + "revenue-aggregation-ignores-order-totals", + "cancel-does-not-restore-stock-fresh-client", + "progression-customer-sees-fulfilment-content", + "catalog-search-requires-exact-name", + "completed-restock-is-replayed", + "profile-read-is-not-owner-scoped", + "promotion-save-drops-bounded-values", + "stock-alert-repeats-while-in-stock", + "direct-purchase-is-attributed-to-another-account", + "support-history-rows-are-hidden", + "queue-ignores-live-fulfilment-updates" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-11d743dd95a4-mongodb-mutation.runs/r1-workers/w7.stdout.log", + "stderr": "ecommerce-l3-11d743dd95a4-mongodb-mutation.runs/r1-workers/w7.stderr.log" + } + }, + { + "index": 7, + "runIndex": 7, + "artifact": "ecommerce-l3-11d743dd95a4-mongodb-mutation.runs/r1-workers/w8.json", + "mutationIds": [ + "purchase-counts-never-affect-ranking", + "live-review-average-uses-an-extra-divisor", + "unpurchased-review-is-accepted", + "cancel-restores-stock-but-keeps-pending-status", + "transfer-debits-source-without-crediting-existing-destination", + "catalog-price-is-offset", + "scheduled-restock-countdown-is-fixed", + "faceted-search-ignores-category", + "customer-can-create-promotion", + "stock-alerts-are-not-owner-scoped", + "concurrent-cart-add-does-not-increment", + "authorized-restock-does-not-change-stock", + "low-stock-boundary-excludes-ten-live" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-11d743dd95a4-mongodb-mutation.runs/r1-workers/w8.stdout.log", + "stderr": "ecommerce-l3-11d743dd95a4-mongodb-mutation.runs/r1-workers/w8.stderr.log" + } + } + ] + } + ], + "stable": true, + "sameImage": true, + "sameHarness": true, + "harnessSha256": "7aa0044000ff319fd5c8b95575d9636a8835ded1afea277d16c7871dd30eadf8", + "qualifiedCheckKeys": [ + "ecommerce.feature.accounts.accounts.1a", + "ecommerce.feature.accounts.accounts.1b", + "ecommerce.feature.accounts.accounts.1c", + "ecommerce.feature.accounts.accounts.1d", + "ecommerce.feature.cart-checkout.cart.4a", + "ecommerce.feature.cart-checkout.cart.4d", + "ecommerce.feature.catalog.catalog-ranking.2b", + "ecommerce.feature.catalog.catalog-search.2d", + "ecommerce.feature.catalog.catalog-values.2a", + "ecommerce.feature.purchasing.purchase-order.3c", + "ecommerce.feature.reviews.reviews.6a", + "ecommerce.feature.warehouse-admin.admin-write.103a", + "ecommerce.feature.warehouse-admin.warehouse-view.7b", + "ecommerce.inventory-operations.operational-views.5c", + "ecommerce.inventory-operations.operational-views.5d", + "ecommerce.inventory-operations.operational-views.5e", + "ecommerce.inventory-operations.operational-views.5f", + "ecommerce.inventory-operations.shipping-accounting.202e", + "ecommerce.inventory-operations.stock-conservation.202a", + "ecommerce.inventory-operations.stock-conservation.202b", + "ecommerce.inventory-operations.stock-conservation.202c", + "ecommerce.inventory-operations.stock-conservation.202d", + "ecommerce.inventory-operations.warehouse-transfer.2a", + "ecommerce.l3.deferred-access.scheduled-work-access.317a", + "ecommerce.l3.deferred-durability.restart-survival.311a", + "ecommerce.l3.deferred-integrity.exactly-once.311a", + "ecommerce.l3.scheduled-restocks.scheduled-restocks.302a", + "ecommerce.l3.scheduled-restocks.scheduled-restocks.305a", + "ecommerce.l3.scheduled-restocks.scheduled-restocks.306a", + "ecommerce.l3.server-time.server-time.312a", + "ecommerce.operations-access.fulfilment-queue.1b", + "ecommerce.operations-access.fulfilment-queue.1c", + "ecommerce.operations-access.operator-authorization.201a", + "ecommerce.operations-access.operator-authorization.201c", + "ecommerce.operations-access.order-owner.204a", + "ecommerce.progression.catalog-management.catalog-management.622a", + "ecommerce.progression.catalog-management.catalog-management.622b", + "ecommerce.progression.customer-profile.customer-profile.620c", + "ecommerce.progression.faceted-search.faceted-search.401a", + "ecommerce.progression.faceted-search.faceted-search.402a", + "ecommerce.progression.managed-support.managed-support.613c", + "ecommerce.progression.notification-preferences.notification-preferences.630c", + "ecommerce.progression.promotion-rules.promotion-rule-values.620a", + "ecommerce.progression.review-access-specifications.review-eligibility-direct.618a", + "ecommerce.progression.staff-access.staff-access.601a", + "ecommerce.progression.staff-roles.staff-roles.621c", + "ecommerce.progression.stock-alerts.stock-alert-delivery.631c", + "ecommerce.progression.support-history.support-history.612c", + "ecommerce.progression.support-intake.support-intake.610a", + "ecommerce.progression.support-triage.support-assignment.611a", + "ecommerce.progression.support-triage.support-priority.611b", + "ecommerce.progression.support-triage.support-status.611c", + "ecommerce.returns-pricing.cancellation-and-return.3a", + "ecommerce.returns-pricing.cancellation-and-return.3b", + "ecommerce.returns-pricing.refund-accounting.203a", + "ecommerce.spec.access-control.cart-boundary.109a", + "ecommerce.spec.access-control.cart-boundary.109b", + "ecommerce.spec.access-control.customer-profile-privacy.620b", + "ecommerce.spec.access-control.fulfilment-area-boundary.1d", + "ecommerce.spec.access-control.managed-support-privacy.613b", + "ecommerce.spec.access-control.notification-preferences-privacy.630b", + "ecommerce.spec.access-control.order-ownership.106a", + "ecommerce.spec.access-control.promotion-management-boundary.620b", + "ecommerce.spec.access-control.purchase-attribution.102a", + "ecommerce.spec.access-control.purchase-session.101a", + "ecommerce.spec.access-control.review-eligibility.108a", + "ecommerce.spec.access-control.review-eligibility.108b", + "ecommerce.spec.access-control.signed-out-purchase.3a", + "ecommerce.spec.access-control.staff-area-boundary.601b", + "ecommerce.spec.access-control.staff-role-boundary.621b", + "ecommerce.spec.access-control.staff-role-revocation.621d", + "ecommerce.spec.access-control.stock-alert-privacy.631b", + "ecommerce.spec.access-control.support-history-logout.612d", + "ecommerce.spec.access-control.support-history-privacy.612b", + "ecommerce.spec.access-control.warehouse-area-boundary.7a", + "ecommerce.spec.access-control.warehouse-write-boundary.103b", + "ecommerce.spec.concurrency-safety.duplicate-checkout.203a", + "ecommerce.spec.concurrency-safety.duplicate-checkout.203b", + "ecommerce.spec.concurrency-safety.last-unit.201a", + "ecommerce.spec.concurrency-safety.last-unit.201b", + "ecommerce.spec.concurrency-safety.last-unit.201c", + "ecommerce.spec.concurrency-safety.restock-race.202a", + "ecommerce.spec.external-data-sync.external-stock.901a", + "ecommerce.spec.external-data-sync.external-stock.901c", + "ecommerce.spec.external-data-sync.external-stock.901d", + "ecommerce.spec.live-state.fulfilment-queue.1a", + "ecommerce.spec.live-state.inventory-dashboard.5a", + "ecommerce.spec.live-state.managed-support.613a", + "ecommerce.spec.live-state.open-list.902a", + "ecommerce.spec.live-state.purchase-stock.3b", + "ecommerce.spec.live-state.ranking.2c", + "ecommerce.spec.live-state.rating.6c", + "ecommerce.spec.live-state.sales-dashboard.5b", + "ecommerce.spec.live-state.shared-cart.4c", + "ecommerce.spec.live-state.stock-transfers.2b", + "ecommerce.spec.live-state.warehouse-stock.7c", + "ecommerce.spec.search-ordering.search-ordering.402b", + "ecommerce.spec.state-durability.account-state-recovery.105a", + "ecommerce.spec.state-durability.account-state-recovery.105b", + "ecommerce.spec.state-durability.cart-reload.4b", + "ecommerce.spec.state-durability.customer-profile-reload.620a", + "ecommerce.spec.state-durability.notification-preferences-reload.630a", + "ecommerce.spec.state-durability.session-reload.1e", + "ecommerce.spec.state-durability.staff-role-reload.621a", + "ecommerce.spec.state-durability.support-history-reload.612a", + "ecommerce.spec.transactional-integrity.books-balance.107a", + "ecommerce.spec.transactional-integrity.books-balance.107b", + "ecommerce.spec.transactional-integrity.server-price.104a", + "ecommerce.spec.transactional-integrity.stock-alert-deduplication.631a", + "ecommerce.spec.transactional-integrity.stock-transfer-overdraw.2c", + "ecommerce.spec.transactional-integrity.unique-review.6b" + ], + "featureCatalog": { + "contentSha256": "863e2a2b09f7b00d1b9755607347364e3ad9013d0ceea58ceca93b1f933f3e45", + "id": "ecommerce.questlines" + }, + "diagnostic": false, + "ok": true + } +} diff --git a/tools/stack-bench/qualification-evidence/ecommerce-l3-43d01f644/mongodb-reference.json b/tools/stack-bench/qualification-evidence/ecommerce-l3-43d01f644/mongodb-reference.json new file mode 100644 index 00000000000..891003682bf --- /dev/null +++ b/tools/stack-bench/qualification-evidence/ecommerce-l3-43d01f644/mongodb-reference.json @@ -0,0 +1,733 @@ +{ + "artifactSchemaVersion": 2, + "kind": "reference_qualification", + "id": "reference-live-mongodb-20260916171514-31-reference", + "attempt": { + "id": "reference-live-mongodb-20260916171514-31-reference", + "parentId": null + }, + "timestamps": { + "startedAt": "2026-09-16T17:15:14.926Z", + "completedAt": "2026-09-16T18:02:51.515Z" + }, + "identities": { + "engine": { + "id": "stack-bench", + "sha256": "31ffc8e48b22c397d10aa5ca2b6bc0680e9ae20fd8903bccc4d7db406a1478de" + }, + "recipe": { + "id": "ecommerce.progression-catalog", + "sha256": "11d743dd95a4671bdbb71c10f75b8405671f20a32c5312c9832c8ff9481e7ed5" + }, + "fixture": { + "id": "ecommerce-reference-mongodb", + "sha256": "5871985671a9aba778c29954b7b5eb04e45030332e1c809767594bf8ac6c6b11" + }, + "calibration": { + "id": "ecommerce.dependency-l3-calibration", + "sha256": "578942627b3d6827609fb623361e1a672b4a602b65e0f1c501048b346438e954" + }, + "experiment": null, + "agentAdapter": null, + "stackAdapter": { + "id": "mongodb", + "sha256": null + }, + "packs": [] + }, + "payload": { + "fixture": "ecommerce-reference-mongodb", + "fixtureSha256": "5871985671a9aba778c29954b7b5eb04e45030332e1c809767594bf8ac6c6b11", + "requiredRepetitions": 1, + "isolation": "docker", + "runner": { + "schemaVersion": 1, + "mode": "appliance", + "platform": "linux", + "architecture": "x64", + "hostname": "docker-desktop", + "dockerEngineVersion": "29.6.2", + "dockerOs": "linux", + "dockerArchitecture": "x86_64", + "kernelVersion": "6.6.87.2-microsoft-standard-WSL2", + "cpuCount": 32, + "memoryBytes": 49232846848, + "containersRunning": 12, + "packageRegistry": "http://127.0.0.1:4873/" + }, + "qualificationScope": { + "checksSha256": "adc107253c217dc57e6b0648b083b5762f1358871f2764baad8cacfd3083eb10", + "executableSha256": "e88b41e4ece5607d0ab8175a1bdcbc808323ba00dc3908d0626f51d5888a3d8f", + "kind": "reference", + "mutationSha256": null, + "recipe": { + "contentSha256": "11d743dd95a4671bdbb71c10f75b8405671f20a32c5312c9832c8ff9481e7ed5", + "id": "ecommerce.progression-catalog" + }, + "schemaVersion": 3, + "stack": { + "id": "mongodb", + "reference": { + "id": "ecommerce-reference-mongodb", + "sourceSha256": "5871985671a9aba778c29954b7b5eb04e45030332e1c809767594bf8ac6c6b11" + }, + "version": "1.5.0" + }, + "sha256": "85d3e9c3c00fb9a5c51ff0048af358a2d7d455240716492fa5a5053e8520b611" + }, + "mutationControl": false, + "runs": [ + { + "repetition": 1, + "output": "ecommerce-l3-11d743dd95a4-mongodb-mutation.runs/r1", + "durationMs": 2099670, + "processError": null, + "harnessSha256Before": "7aa0044000ff319fd5c8b95575d9636a8835ded1afea277d16c7871dd30eadf8", + "harnessSha256After": "7aa0044000ff319fd5c8b95575d9636a8835ded1afea277d16c7871dd30eadf8", + "ok": true, + "failures": [], + "runId": "ecommerce-mongodb-run0-20260916171515-ff54de38", + "score": "180/180", + "imageId": "sha256:32ff9a9e519ba9d1af2fe72f24622caa8ca7a9f2baf2338c6b1e0435e6ac5455", + "criteria": 111, + "zeroPointCriteria": 0, + "fingerprint": "01676f87359c0bfc4b294128f48746ef655e9e4b61734439a2ea4b95dc34a605", + "outcome": "passed", + "packRuntime": { + "schemaVersion": 1, + "metric": "pack-check-wall-clock-sum-v1", + "packs": [ + { + "id": "ecommerce.feature.accounts", + "checkCount": 4, + "setupRuntimeMs": 1283, + "criterionRuntimeMs": 15198, + "measuredRuntimeMs": 16481, + "budget": { + "status": "bounded", + "maxRuntimeMs": 18000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.cart", + "checkCount": 1, + "setupRuntimeMs": 664, + "criterionRuntimeMs": 6082, + "measuredRuntimeMs": 6746, + "budget": { + "status": "bounded", + "maxRuntimeMs": 42000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.catalog-discovery", + "checkCount": 2, + "setupRuntimeMs": 0, + "criterionRuntimeMs": 1886, + "measuredRuntimeMs": 1886, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.catalog-items", + "checkCount": 1, + "setupRuntimeMs": 0, + "criterionRuntimeMs": 261, + "measuredRuntimeMs": 261, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.checkout", + "checkCount": 1, + "setupRuntimeMs": 664, + "criterionRuntimeMs": 10856, + "measuredRuntimeMs": 11520, + "budget": { + "status": "bounded", + "maxRuntimeMs": 42000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.purchasing", + "checkCount": 1, + "setupRuntimeMs": 350, + "criterionRuntimeMs": 1181, + "measuredRuntimeMs": 1531, + "budget": { + "status": "bounded", + "maxRuntimeMs": 24000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.reviews", + "checkCount": 1, + "setupRuntimeMs": 21517, + "criterionRuntimeMs": 302, + "measuredRuntimeMs": 21819, + "budget": { + "status": "bounded", + "maxRuntimeMs": 22000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.warehouse-admin", + "checkCount": 2, + "setupRuntimeMs": 1707, + "criterionRuntimeMs": 4360, + "measuredRuntimeMs": 6067, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.inventory-dashboard", + "checkCount": 1, + "setupRuntimeMs": 4396, + "criterionRuntimeMs": 8, + "measuredRuntimeMs": 4404, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.order-cancellation-features", + "checkCount": 2, + "setupRuntimeMs": 1150, + "criterionRuntimeMs": 16379, + "measuredRuntimeMs": 17529, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.recommendations", + "checkCount": 1, + "setupRuntimeMs": 316, + "criterionRuntimeMs": 5174, + "measuredRuntimeMs": 5490, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.sales-dashboard", + "checkCount": 2, + "setupRuntimeMs": 2240, + "criterionRuntimeMs": 5072, + "measuredRuntimeMs": 7312, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.stock-transfers-features", + "checkCount": 1, + "setupRuntimeMs": 582, + "criterionRuntimeMs": 2840, + "measuredRuntimeMs": 3422, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.deferred-access-specifications", + "checkCount": 1, + "setupRuntimeMs": 21136, + "criterionRuntimeMs": 4269, + "measuredRuntimeMs": 25405, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.deferred-durability-specifications", + "checkCount": 1, + "setupRuntimeMs": 128951, + "criterionRuntimeMs": 39300, + "measuredRuntimeMs": 168251, + "budget": { + "status": "bounded", + "maxRuntimeMs": 720000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.deferred-integrity-specifications", + "checkCount": 1, + "setupRuntimeMs": 44688, + "criterionRuntimeMs": 39618, + "measuredRuntimeMs": 84306, + "budget": { + "status": "bounded", + "maxRuntimeMs": 400000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.scheduled-restocks-features", + "checkCount": 3, + "setupRuntimeMs": 61680, + "criterionRuntimeMs": 69330, + "measuredRuntimeMs": 131010, + "budget": { + "status": "bounded", + "maxRuntimeMs": 150000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.server-time-specifications", + "checkCount": 1, + "setupRuntimeMs": 28389, + "criterionRuntimeMs": 112939, + "measuredRuntimeMs": 141328, + "budget": { + "status": "bounded", + "maxRuntimeMs": 300000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.cancellation-accounting-specifications", + "checkCount": 1, + "setupRuntimeMs": 726, + "criterionRuntimeMs": 10936, + "measuredRuntimeMs": 11662, + "budget": { + "status": "bounded", + "maxRuntimeMs": 24000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.catalog-management", + "checkCount": 2, + "setupRuntimeMs": 3442, + "criterionRuntimeMs": 32, + "measuredRuntimeMs": 3474, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.customer-profile", + "checkCount": 1, + "setupRuntimeMs": 509, + "criterionRuntimeMs": 5072, + "measuredRuntimeMs": 5581, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.faceted-search", + "checkCount": 2, + "setupRuntimeMs": 43525, + "criterionRuntimeMs": 25591, + "measuredRuntimeMs": 69116, + "budget": { + "status": "bounded", + "maxRuntimeMs": 141000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.fulfilment-queue", + "checkCount": 2, + "setupRuntimeMs": 1366, + "criterionRuntimeMs": 27315, + "measuredRuntimeMs": 28681, + "budget": { + "status": "bounded", + "maxRuntimeMs": 76000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.inventory-conservation-specifications", + "checkCount": 5, + "setupRuntimeMs": 2534, + "criterionRuntimeMs": 64243, + "measuredRuntimeMs": 66777, + "budget": { + "status": "bounded", + "maxRuntimeMs": 138000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.managed-support", + "checkCount": 1, + "setupRuntimeMs": 1152, + "criterionRuntimeMs": 6142, + "measuredRuntimeMs": 7294, + "budget": { + "status": "bounded", + "maxRuntimeMs": 55000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.notification-preferences", + "checkCount": 1, + "setupRuntimeMs": 809, + "criterionRuntimeMs": 5110, + "measuredRuntimeMs": 5919, + "budget": { + "status": "bounded", + "maxRuntimeMs": 40000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.operations-access-specifications", + "checkCount": 3, + "setupRuntimeMs": 10118, + "criterionRuntimeMs": 38409, + "measuredRuntimeMs": 48527, + "budget": { + "status": "bounded", + "maxRuntimeMs": 98000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.promotion-rules", + "checkCount": 1, + "setupRuntimeMs": 657, + "criterionRuntimeMs": 457, + "measuredRuntimeMs": 1114, + "budget": { + "status": "bounded", + "maxRuntimeMs": 45000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.review-access-specifications", + "checkCount": 1, + "setupRuntimeMs": 23782, + "criterionRuntimeMs": 6734, + "measuredRuntimeMs": 30516, + "budget": { + "status": "bounded", + "maxRuntimeMs": 62000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.staff-access", + "checkCount": 1, + "setupRuntimeMs": 0, + "criterionRuntimeMs": 748, + "measuredRuntimeMs": 748, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.staff-roles", + "checkCount": 1, + "setupRuntimeMs": 624, + "criterionRuntimeMs": 74, + "measuredRuntimeMs": 698, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.stock-alerts", + "checkCount": 1, + "setupRuntimeMs": 5102, + "criterionRuntimeMs": 11458, + "measuredRuntimeMs": 16560, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.support-history", + "checkCount": 1, + "setupRuntimeMs": 1306, + "criterionRuntimeMs": 1310, + "measuredRuntimeMs": 2616, + "budget": { + "status": "bounded", + "maxRuntimeMs": 50000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.support-intake", + "checkCount": 1, + "setupRuntimeMs": 0, + "criterionRuntimeMs": 507, + "measuredRuntimeMs": 507, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.support-triage", + "checkCount": 3, + "setupRuntimeMs": 1063, + "criterionRuntimeMs": 10086, + "measuredRuntimeMs": 11149, + "budget": { + "status": "bounded", + "maxRuntimeMs": 45000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.access-control", + "checkCount": 21, + "setupRuntimeMs": 32179, + "criterionRuntimeMs": 220610, + "measuredRuntimeMs": 252789, + "budget": { + "status": "bounded", + "maxRuntimeMs": 464000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.concurrency-safety", + "checkCount": 6, + "setupRuntimeMs": 27142, + "criterionRuntimeMs": 48985, + "measuredRuntimeMs": 76127, + "budget": { + "status": "bounded", + "maxRuntimeMs": 125000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.external-data-sync", + "checkCount": 3, + "setupRuntimeMs": 636, + "criterionRuntimeMs": 29460, + "measuredRuntimeMs": 30096, + "budget": { + "status": "bounded", + "maxRuntimeMs": 105000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.live-state", + "checkCount": 11, + "setupRuntimeMs": 81184, + "criterionRuntimeMs": 9527, + "measuredRuntimeMs": 90711, + "budget": { + "status": "bounded", + "maxRuntimeMs": 184000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.search-ordering", + "checkCount": 1, + "setupRuntimeMs": 21728, + "criterionRuntimeMs": 5183, + "measuredRuntimeMs": 26911, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.state-durability", + "checkCount": 8, + "setupRuntimeMs": 5795, + "criterionRuntimeMs": 74795, + "measuredRuntimeMs": 80590, + "budget": { + "status": "bounded", + "maxRuntimeMs": 408000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.transactional-integrity", + "checkCount": 6, + "setupRuntimeMs": 45804, + "criterionRuntimeMs": 39676, + "measuredRuntimeMs": 85480, + "budget": { + "status": "bounded", + "maxRuntimeMs": 100000 + }, + "exceeded": false + } + ] + }, + "mutations": null + } + ], + "stable": true, + "sameImage": true, + "sameHarness": true, + "harnessSha256": "7aa0044000ff319fd5c8b95575d9636a8835ded1afea277d16c7871dd30eadf8", + "qualifiedCheckKeys": [ + "ecommerce.feature.accounts.accounts.1a", + "ecommerce.feature.accounts.accounts.1b", + "ecommerce.feature.accounts.accounts.1c", + "ecommerce.feature.accounts.accounts.1d", + "ecommerce.feature.cart-checkout.cart.4a", + "ecommerce.feature.cart-checkout.cart.4d", + "ecommerce.feature.catalog.catalog-ranking.2b", + "ecommerce.feature.catalog.catalog-search.2d", + "ecommerce.feature.catalog.catalog-values.2a", + "ecommerce.feature.purchasing.purchase-order.3c", + "ecommerce.feature.reviews.reviews.6a", + "ecommerce.feature.warehouse-admin.admin-write.103a", + "ecommerce.feature.warehouse-admin.warehouse-view.7b", + "ecommerce.inventory-operations.operational-views.5c", + "ecommerce.inventory-operations.operational-views.5d", + "ecommerce.inventory-operations.operational-views.5e", + "ecommerce.inventory-operations.operational-views.5f", + "ecommerce.inventory-operations.shipping-accounting.202e", + "ecommerce.inventory-operations.stock-conservation.202a", + "ecommerce.inventory-operations.stock-conservation.202b", + "ecommerce.inventory-operations.stock-conservation.202c", + "ecommerce.inventory-operations.stock-conservation.202d", + "ecommerce.inventory-operations.warehouse-transfer.2a", + "ecommerce.l3.deferred-access.scheduled-work-access.317a", + "ecommerce.l3.deferred-durability.restart-survival.311a", + "ecommerce.l3.deferred-integrity.exactly-once.311a", + "ecommerce.l3.scheduled-restocks.scheduled-restocks.302a", + "ecommerce.l3.scheduled-restocks.scheduled-restocks.305a", + "ecommerce.l3.scheduled-restocks.scheduled-restocks.306a", + "ecommerce.l3.server-time.server-time.312a", + "ecommerce.operations-access.fulfilment-queue.1b", + "ecommerce.operations-access.fulfilment-queue.1c", + "ecommerce.operations-access.operator-authorization.201a", + "ecommerce.operations-access.operator-authorization.201c", + "ecommerce.operations-access.order-owner.204a", + "ecommerce.progression.catalog-management.catalog-management.622a", + "ecommerce.progression.catalog-management.catalog-management.622b", + "ecommerce.progression.customer-profile.customer-profile.620c", + "ecommerce.progression.faceted-search.faceted-search.401a", + "ecommerce.progression.faceted-search.faceted-search.402a", + "ecommerce.progression.managed-support.managed-support.613c", + "ecommerce.progression.notification-preferences.notification-preferences.630c", + "ecommerce.progression.promotion-rules.promotion-rule-values.620a", + "ecommerce.progression.review-access-specifications.review-eligibility-direct.618a", + "ecommerce.progression.staff-access.staff-access.601a", + "ecommerce.progression.staff-roles.staff-roles.621c", + "ecommerce.progression.stock-alerts.stock-alert-delivery.631c", + "ecommerce.progression.support-history.support-history.612c", + "ecommerce.progression.support-intake.support-intake.610a", + "ecommerce.progression.support-triage.support-assignment.611a", + "ecommerce.progression.support-triage.support-priority.611b", + "ecommerce.progression.support-triage.support-status.611c", + "ecommerce.returns-pricing.cancellation-and-return.3a", + "ecommerce.returns-pricing.cancellation-and-return.3b", + "ecommerce.returns-pricing.refund-accounting.203a", + "ecommerce.spec.access-control.cart-boundary.109a", + "ecommerce.spec.access-control.cart-boundary.109b", + "ecommerce.spec.access-control.customer-profile-privacy.620b", + "ecommerce.spec.access-control.fulfilment-area-boundary.1d", + "ecommerce.spec.access-control.managed-support-privacy.613b", + "ecommerce.spec.access-control.notification-preferences-privacy.630b", + "ecommerce.spec.access-control.order-ownership.106a", + "ecommerce.spec.access-control.promotion-management-boundary.620b", + "ecommerce.spec.access-control.purchase-attribution.102a", + "ecommerce.spec.access-control.purchase-session.101a", + "ecommerce.spec.access-control.review-eligibility.108a", + "ecommerce.spec.access-control.review-eligibility.108b", + "ecommerce.spec.access-control.signed-out-purchase.3a", + "ecommerce.spec.access-control.staff-area-boundary.601b", + "ecommerce.spec.access-control.staff-role-boundary.621b", + "ecommerce.spec.access-control.staff-role-revocation.621d", + "ecommerce.spec.access-control.stock-alert-privacy.631b", + "ecommerce.spec.access-control.support-history-logout.612d", + "ecommerce.spec.access-control.support-history-privacy.612b", + "ecommerce.spec.access-control.warehouse-area-boundary.7a", + "ecommerce.spec.access-control.warehouse-write-boundary.103b", + "ecommerce.spec.concurrency-safety.duplicate-checkout.203a", + "ecommerce.spec.concurrency-safety.duplicate-checkout.203b", + "ecommerce.spec.concurrency-safety.last-unit.201a", + "ecommerce.spec.concurrency-safety.last-unit.201b", + "ecommerce.spec.concurrency-safety.last-unit.201c", + "ecommerce.spec.concurrency-safety.restock-race.202a", + "ecommerce.spec.external-data-sync.external-stock.901a", + "ecommerce.spec.external-data-sync.external-stock.901c", + "ecommerce.spec.external-data-sync.external-stock.901d", + "ecommerce.spec.live-state.fulfilment-queue.1a", + "ecommerce.spec.live-state.inventory-dashboard.5a", + "ecommerce.spec.live-state.managed-support.613a", + "ecommerce.spec.live-state.open-list.902a", + "ecommerce.spec.live-state.purchase-stock.3b", + "ecommerce.spec.live-state.ranking.2c", + "ecommerce.spec.live-state.rating.6c", + "ecommerce.spec.live-state.sales-dashboard.5b", + "ecommerce.spec.live-state.shared-cart.4c", + "ecommerce.spec.live-state.stock-transfers.2b", + "ecommerce.spec.live-state.warehouse-stock.7c", + "ecommerce.spec.search-ordering.search-ordering.402b", + "ecommerce.spec.state-durability.account-state-recovery.105a", + "ecommerce.spec.state-durability.account-state-recovery.105b", + "ecommerce.spec.state-durability.cart-reload.4b", + "ecommerce.spec.state-durability.customer-profile-reload.620a", + "ecommerce.spec.state-durability.notification-preferences-reload.630a", + "ecommerce.spec.state-durability.session-reload.1e", + "ecommerce.spec.state-durability.staff-role-reload.621a", + "ecommerce.spec.state-durability.support-history-reload.612a", + "ecommerce.spec.transactional-integrity.books-balance.107a", + "ecommerce.spec.transactional-integrity.books-balance.107b", + "ecommerce.spec.transactional-integrity.server-price.104a", + "ecommerce.spec.transactional-integrity.stock-alert-deduplication.631a", + "ecommerce.spec.transactional-integrity.stock-transfer-overdraw.2c", + "ecommerce.spec.transactional-integrity.unique-review.6b" + ], + "featureCatalog": { + "contentSha256": "863e2a2b09f7b00d1b9755607347364e3ad9013d0ceea58ceca93b1f933f3e45", + "id": "ecommerce.questlines" + }, + "diagnostic": false, + "ok": true + } +} diff --git a/tools/stack-bench/qualification-evidence/ecommerce-l3-43d01f644/null.json b/tools/stack-bench/qualification-evidence/ecommerce-l3-43d01f644/null.json new file mode 100644 index 00000000000..6f92c42ba89 --- /dev/null +++ b/tools/stack-bench/qualification-evidence/ecommerce-l3-43d01f644/null.json @@ -0,0 +1,1655 @@ +{ + "artifactSchemaVersion": 2, + "kind": "null_control", + "id": "null-control-2026-09-16T17-15-15-729Z", + "attempt": { + "id": "null-control-2026-09-16T17-15-15-729Z", + "parentId": null + }, + "timestamps": { + "startedAt": "2026-09-16T17:15:15.730Z", + "completedAt": "2026-09-16T17:22:58.576Z" + }, + "identities": { + "engine": { + "id": "stack-bench", + "sha256": "31ffc8e48b22c397d10aa5ca2b6bc0680e9ae20fd8903bccc4d7db406a1478de" + }, + "recipe": { + "id": "ecommerce.progression-catalog", + "sha256": "11d743dd95a4671bdbb71c10f75b8405671f20a32c5312c9832c8ff9481e7ed5" + }, + "fixture": null, + "calibration": { + "id": "ecommerce.dependency-l3-calibration", + "sha256": "578942627b3d6827609fb623361e1a672b4a602b65e0f1c501048b346438e954" + }, + "experiment": null, + "agentAdapter": null, + "stackAdapter": null, + "packs": [] + }, + "payload": { + "durationMs": 462846, + "runner": { + "schemaVersion": 1, + "mode": "appliance", + "platform": "linux", + "architecture": "x64", + "hostname": "docker-desktop", + "dockerEngineVersion": "29.6.2", + "dockerOs": "linux", + "dockerArchitecture": "x86_64", + "kernelVersion": "6.6.87.2-microsoft-standard-WSL2", + "cpuCount": 32, + "memoryBytes": 49232846848, + "containersRunning": 21, + "packageRegistry": "http://127.0.0.1:4873/" + }, + "qualificationScope": { + "checksSha256": "adc107253c217dc57e6b0648b083b5762f1358871f2764baad8cacfd3083eb10", + "executableSha256": "11456feb540706b19e72b54d6fb95420563bc3cc2517a851055be717f44ec2a0", + "kind": "null", + "mutationSha256": null, + "recipe": { + "contentSha256": "11d743dd95a4671bdbb71c10f75b8405671f20a32c5312c9832c8ff9481e7ed5", + "id": "ecommerce.progression-catalog" + }, + "schemaVersion": 3, + "stack": null, + "sha256": "db40c3284471445fa8e87b7b366297586d194507e14f9e35ed3dcde212cebfaf" + }, + "tracks": [ + "ecommerce" + ], + "ok": true, + "summary": { + "criteria": 111, + "points": 180, + "expectedFailures": { + "criteria": 111, + "points": 180 + }, + "expectedFailureStages": { + "setup": { + "criteria": 104, + "points": 170 + }, + "assertion": { + "criteria": 7, + "points": 10 + } + }, + "vacuousPasses": { + "criteria": 0, + "points": 0 + }, + "oracleGaps": { + "criteria": 0, + "points": 0 + }, + "unscored": { + "criteria": 0, + "passed": 0, + "failed": 0, + "inconclusive": 0 + } + }, + "criteria": [ + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-001", + "scenario": "scenarios/01-account-create.json", + "feature": 1, + "featureName": "Accounts", + "criterion": "1a", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "failed", + "failureStage": "assertion", + "detail": "none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-002", + "scenario": "scenarios/01-account-duplicate.json", + "feature": 1, + "featureName": "Accounts", + "criterion": "1b", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-003", + "scenario": "scenarios/01-account-password.json", + "feature": 1, + "featureName": "Accounts", + "criterion": "1c", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-004", + "scenario": "scenarios/01-account-reload.json", + "feature": 1, + "featureName": "Accounts", + "criterion": "1e", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-005", + "scenario": "scenarios/01-account-signout.json", + "feature": 1, + "featureName": "Accounts", + "criterion": "1d", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-006", + "scenario": "scenarios/01-admin-write-staff.json", + "feature": 103, + "featureName": "Only an administrator can restock", + "criterion": "103a", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-006", + "scenario": "scenarios/01-admin-write-staff.json", + "feature": 103, + "featureName": "Only an administrator can restock", + "criterion": "103b", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-007", + "scenario": "scenarios/01-buying.json", + "feature": 3, + "featureName": "Buying", + "criterion": "3b", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-008", + "scenario": "scenarios/01-cart-boundary.json", + "feature": 109, + "featureName": "A cart is nobody else's business", + "criterion": "109a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-008", + "scenario": "scenarios/01-cart-boundary.json", + "feature": 109, + "featureName": "A cart is nobody else's business", + "criterion": "109b", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-009", + "scenario": "scenarios/01-cart.json", + "feature": 4, + "featureName": "Cart belongs to the account", + "criterion": "4b", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-009", + "scenario": "scenarios/01-cart.json", + "feature": 4, + "featureName": "Cart belongs to the account", + "criterion": "4c", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-010", + "scenario": "scenarios/01-catalog-ranking.json", + "feature": 2, + "featureName": "Public catalog ranking", + "criterion": "2b", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "failed", + "failureStage": "assertion", + "detail": "the item-name control entries are not in the required order" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-011", + "scenario": "scenarios/01-catalog-search.json", + "feature": 2, + "featureName": "Public catalog search", + "criterion": "2d", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "failed", + "failureStage": "assertion", + "detail": "the search-input control did not become available in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-012", + "scenario": "scenarios/01-catalog-values.json", + "feature": 2, + "featureName": "Public catalog values", + "criterion": "2a", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "failed", + "failureStage": "assertion", + "detail": "the item-card control matching \"Air Purifier\" did not appear" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-013", + "scenario": "scenarios/01-core.json", + "feature": 2, + "featureName": "Storefront is public and live", + "criterion": "2c", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-014", + "scenario": "scenarios/01-duplicate-checkout.json", + "feature": 203, + "featureName": "One cart, two tabs, one checkout", + "criterion": "203a", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-014", + "scenario": "scenarios/01-duplicate-checkout.json", + "feature": 203, + "featureName": "One cart, two tabs, one checkout", + "criterion": "203b", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-015", + "scenario": "scenarios/01-external-live-sync.json", + "feature": 901, + "featureName": "An open storefront follows a direct database write", + "criterion": "901a", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: the item-stock control inside the item-card control in the entry matching \"Desk Lamp\" did not appear" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-016", + "scenario": "scenarios/01-external-reconnect-sync.json", + "feature": 901, + "featureName": "A reconnecting storefront catches up to an external write", + "criterion": "901d", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: the item-stock control inside the item-card control in the entry matching \"Desk Lamp\" did not appear" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-018", + "scenario": "scenarios/01-external-server-restart-sync.json", + "feature": 901, + "featureName": "An open storefront catches up after its server restarts", + "criterion": "901c", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: the item-stock control inside the item-card control in the entry matching \"Desk Lamp\" did not appear" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-019", + "scenario": "scenarios/01-last-unit.json", + "feature": 201, + "featureName": "The last unit is sold once", + "criterion": "201a", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-019", + "scenario": "scenarios/01-last-unit.json", + "feature": 201, + "featureName": "The last unit is sold once", + "criterion": "201b", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-019", + "scenario": "scenarios/01-last-unit.json", + "feature": 201, + "featureName": "The last unit is sold once", + "criterion": "201c", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-020", + "scenario": "scenarios/01-order-ownership.json", + "feature": 106, + "featureName": "One customer's orders are not another's", + "criterion": "106a", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-021", + "scenario": "scenarios/01-purchase-attribution.json", + "feature": 102, + "featureName": "Purchases are attributed to whoever made them", + "criterion": "102a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-022", + "scenario": "scenarios/01-purchase-session.json", + "feature": 101, + "featureName": "Purchase requires an account", + "criterion": "101a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-023", + "scenario": "scenarios/01-restock-race.json", + "feature": 202, + "featureName": "A restock during a rush is not lost", + "criterion": "202a", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-024", + "scenario": "scenarios/01-review-eligibility.json", + "feature": 108, + "featureName": "A review is a claim about a purchase", + "criterion": "108a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-024", + "scenario": "scenarios/01-review-eligibility.json", + "feature": 108, + "featureName": "A review is a claim about a purchase", + "criterion": "108b", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-025", + "scenario": "scenarios/01-review-rating-live.json", + "feature": 6, + "featureName": "Reviews", + "criterion": "6c", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-026", + "scenario": "scenarios/01-review-uniqueness.json", + "feature": 6, + "featureName": "Reviews", + "criterion": "6b", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-027", + "scenario": "scenarios/01-review-visibility.json", + "feature": 6, + "featureName": "Reviews", + "criterion": "6a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-028", + "scenario": "scenarios/01-server-price.json", + "feature": 104, + "featureName": "The price is the store's to set", + "criterion": "104a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-029", + "scenario": "scenarios/01-warehouse-admin-staff.json", + "feature": 7, + "featureName": "Admin and warehouses", + "criterion": "7a", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-029", + "scenario": "scenarios/01-warehouse-admin-staff.json", + "feature": 7, + "featureName": "Admin and warehouses", + "criterion": "7b", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-030", + "scenario": "scenarios/01-warehouse-stock-live-staff.json", + "feature": 7, + "featureName": "Warehouse stock stays live", + "criterion": "7c", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-032", + "scenario": "scenarios/02-fulfilment-access.json", + "feature": 1, + "featureName": "Fulfilment area access", + "criterion": "1d", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-033", + "scenario": "scenarios/02-fulfilment-live.json", + "feature": 1, + "featureName": "Live fulfilment queue", + "criterion": "1a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-034", + "scenario": "scenarios/02-fulfilment-ship.json", + "feature": 1, + "featureName": "Ship a pending order", + "criterion": "1c", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-035", + "scenario": "scenarios/02-invariants.json", + "feature": 203, + "featureName": "The books still balance once money can flow backwards", + "criterion": "203a", + "points": 3, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-037", + "scenario": "scenarios/02-low-stock.json", + "feature": 5, + "featureName": "The low-stock view", + "criterion": "5e", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-037", + "scenario": "scenarios/02-low-stock.json", + "feature": 5, + "featureName": "The low-stock view", + "criterion": "5a", + "points": 3, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-038", + "scenario": "scenarios/02-operational-best-sellers.json", + "feature": 5, + "featureName": "Signed-out best sellers", + "criterion": "5d", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-039", + "scenario": "scenarios/02-operational-category-totals.json", + "feature": 5, + "featureName": "Category sales totals", + "criterion": "5f", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-039", + "scenario": "scenarios/02-operational-category-totals.json", + "feature": 5, + "featureName": "Category sales totals", + "criterion": "5b", + "points": 3, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-040", + "scenario": "scenarios/02-operational-recommendations.json", + "feature": 5, + "featureName": "Customer recommendations", + "criterion": "5c", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-041", + "scenario": "scenarios/02-order-cancellation-core.json", + "feature": 3, + "featureName": "Cancel a pending order", + "criterion": "3a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-042", + "scenario": "scenarios/02-order-cancellation-history.json", + "feature": 3, + "featureName": "Cancellation history", + "criterion": "3b", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-044", + "scenario": "scenarios/02-queue-warehouse.json", + "feature": 1, + "featureName": "Fulfilment queue", + "criterion": "1b", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-045", + "scenario": "scenarios/02-self-contained.json", + "feature": 202, + "featureName": "Stock recovery is durable across clients", + "criterion": "202b", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-045", + "scenario": "scenarios/02-self-contained.json", + "feature": 202, + "featureName": "Stock recovery is durable across clients", + "criterion": "202c", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-046", + "scenario": "scenarios/02-server-actions.json", + "feature": 201, + "featureName": "Shipping requires an operator", + "criterion": "201c", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-046", + "scenario": "scenarios/02-server-actions.json", + "feature": 202, + "featureName": "Stock is conserved while operations overlap", + "criterion": "202d", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-046", + "scenario": "scenarios/02-server-actions.json", + "feature": 204, + "featureName": "An order belongs to the person who placed it", + "criterion": "204a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-047", + "scenario": "scenarios/02-strengthened.json", + "feature": 2, + "featureName": "Moving stock between warehouses", + "criterion": "2a", + "points": 3, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-047", + "scenario": "scenarios/02-strengthened.json", + "feature": 201, + "featureName": "Operating the store requires authorization", + "criterion": "201a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-047", + "scenario": "scenarios/02-strengthened.json", + "feature": 202, + "featureName": "Stock is conserved however it moves", + "criterion": "202a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-048", + "scenario": "scenarios/02-transfer-overdraw.json", + "feature": 2, + "featureName": "Moving stock between warehouses", + "criterion": "2c", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-049", + "scenario": "scenarios/02-transfer-totals.json", + "feature": 2, + "featureName": "Warehouse totals", + "criterion": "2b", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-051", + "scenario": "scenarios/03-deferred-access.json", + "feature": 317, + "featureName": "Customers cannot manage scheduled restocks", + "criterion": "317a", + "points": 3, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-052", + "scenario": "scenarios/03-deferred-durability.json", + "feature": 311, + "featureName": "A scheduled restock survives restart", + "criterion": "311a", + "points": 4, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-053", + "scenario": "scenarios/03-deferred-integrity.json", + "feature": 311, + "featureName": "A restock applies once", + "criterion": "311a", + "points": 3, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-056", + "scenario": "scenarios/03-scheduled-restock-apply.json", + "feature": 305, + "featureName": "A due restock applies", + "criterion": "305a", + "points": 3, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-057", + "scenario": "scenarios/03-scheduled-restock-cancel.json", + "feature": 306, + "featureName": "A scheduled restock can be cancelled", + "criterion": "306a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-058", + "scenario": "scenarios/03-scheduled-restocks.json", + "feature": 302, + "featureName": "A restock is pending before it is due", + "criterion": "302a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-059", + "scenario": "scenarios/03-server-time.json", + "feature": 312, + "featureName": "Restart does not run work early", + "criterion": "312a", + "points": 3, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-060", + "scenario": "scenarios/progression-account-state-reconnect.json", + "feature": 105, + "featureName": "An account keeps what belongs to it", + "criterion": "105b", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-061", + "scenario": "scenarios/progression-account-state-reload.json", + "feature": 105, + "featureName": "An account keeps what belongs to it", + "criterion": "105a", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-065", + "scenario": "scenarios/progression-books-balance.json", + "feature": 107, + "featureName": "The books balance", + "criterion": "107a", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-065", + "scenario": "scenarios/progression-books-balance.json", + "feature": 107, + "featureName": "The books balance", + "criterion": "107b", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-068", + "scenario": "scenarios/progression-cart-checkout.json", + "feature": 4, + "featureName": "Account cart and checkout", + "criterion": "4a", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-068", + "scenario": "scenarios/progression-cart-checkout.json", + "feature": 4, + "featureName": "Account cart and checkout", + "criterion": "4d", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-070", + "scenario": "scenarios/progression-catalog-management.json", + "feature": 622, + "featureName": "Catalog management", + "criterion": "622a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-070", + "scenario": "scenarios/progression-catalog-management.json", + "feature": 622, + "featureName": "Catalog management", + "criterion": "622b", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-072", + "scenario": "scenarios/progression-customer-profile.json", + "feature": 620, + "featureName": "Customer profile", + "criterion": "620c", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-072", + "scenario": "scenarios/progression-customer-profile.json", + "feature": 620, + "featureName": "Customer profile", + "criterion": "620a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-072", + "scenario": "scenarios/progression-customer-profile.json", + "feature": 620, + "featureName": "Customer profile", + "criterion": "620b", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-074", + "scenario": "scenarios/progression-faceted-filters.json", + "feature": 401, + "featureName": "Filters compose", + "criterion": "401a", + "points": 3, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: the category-filter control did not become available in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-075", + "scenario": "scenarios/progression-faceted-pagination.json", + "feature": 402, + "featureName": "Pages are stable", + "criterion": "402a", + "points": 3, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: the minimum-price control did not become available in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-076", + "scenario": "scenarios/progression-managed-support-privacy.json", + "feature": 613, + "featureName": "Managed support privacy", + "criterion": "613b", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-077", + "scenario": "scenarios/progression-managed-support-shared.json", + "feature": 613, + "featureName": "Shared managed support case", + "criterion": "613c", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-077", + "scenario": "scenarios/progression-managed-support-shared.json", + "feature": 613, + "featureName": "Shared managed support case", + "criterion": "613a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-078", + "scenario": "scenarios/progression-notification-preferences.json", + "feature": 630, + "featureName": "Account notification preferences", + "criterion": "630c", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-078", + "scenario": "scenarios/progression-notification-preferences.json", + "feature": 630, + "featureName": "Account notification preferences", + "criterion": "630a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-078", + "scenario": "scenarios/progression-notification-preferences.json", + "feature": 630, + "featureName": "Account notification preferences", + "criterion": "630b", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-079", + "scenario": "scenarios/progression-open-list-live.json", + "feature": 902, + "featureName": "An open list stays current", + "criterion": "902a", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-089", + "scenario": "scenarios/progression-promotion-rules.json", + "feature": 620, + "featureName": "Staff-managed promotion rules", + "criterion": "620a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-089", + "scenario": "scenarios/progression-promotion-rules.json", + "feature": 620, + "featureName": "Staff-managed promotion rules", + "criterion": "620b", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-090", + "scenario": "scenarios/progression-purchasing.json", + "feature": 3, + "featureName": "Purchase order history", + "criterion": "3c", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-092", + "scenario": "scenarios/progression-review-access.json", + "feature": 618, + "featureName": "Review access", + "criterion": "618a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-093", + "scenario": "scenarios/progression-search-ordering.json", + "feature": 402, + "featureName": "Purchases preserve search ordering", + "criterion": "402b", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-094", + "scenario": "scenarios/progression-shipping-accounting.json", + "feature": 202, + "featureName": "Shipping preserves completed purchase accounting", + "criterion": "202e", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-095", + "scenario": "scenarios/progression-signed-out-purchase.json", + "feature": 3, + "featureName": "Buying", + "criterion": "3a", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: the item-card control matching \"Keyboard\" did not appear" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-097", + "scenario": "scenarios/progression-staff-access.json", + "feature": 601, + "featureName": "Staff access", + "criterion": "601a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "failed", + "failureStage": "assertion", + "detail": "none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-097", + "scenario": "scenarios/progression-staff-access.json", + "feature": 601, + "featureName": "Staff access", + "criterion": "601b", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "failed", + "failureStage": "assertion", + "detail": "none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-099", + "scenario": "scenarios/progression-staff-roles.json", + "feature": 621, + "featureName": "Staff roles", + "criterion": "621c", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-099", + "scenario": "scenarios/progression-staff-roles.json", + "feature": 621, + "featureName": "Staff roles", + "criterion": "621a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-099", + "scenario": "scenarios/progression-staff-roles.json", + "feature": 621, + "featureName": "Staff roles", + "criterion": "621b", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-099", + "scenario": "scenarios/progression-staff-roles.json", + "feature": 621, + "featureName": "Staff roles", + "criterion": "621d", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-100", + "scenario": "scenarios/progression-stock-alert-delivery.json", + "feature": 631, + "featureName": "Stock alert delivery", + "criterion": "631c", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-101", + "scenario": "scenarios/progression-stock-alerts.json", + "feature": 631, + "featureName": "Private one-time stock alerts", + "criterion": "631a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-101", + "scenario": "scenarios/progression-stock-alerts.json", + "feature": 631, + "featureName": "Private one-time stock alerts", + "criterion": "631b", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-105", + "scenario": "scenarios/progression-support-history.json", + "feature": 612, + "featureName": "Customer support history", + "criterion": "612c", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-105", + "scenario": "scenarios/progression-support-history.json", + "feature": 612, + "featureName": "Customer support history", + "criterion": "612a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-105", + "scenario": "scenarios/progression-support-history.json", + "feature": 612, + "featureName": "Customer support history", + "criterion": "612b", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-105", + "scenario": "scenarios/progression-support-history.json", + "feature": 612, + "featureName": "Customer support history", + "criterion": "612d", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-106", + "scenario": "scenarios/progression-support-intake.json", + "feature": 610, + "featureName": "Support intake", + "criterion": "610a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "failed", + "failureStage": "assertion", + "detail": "the support-link control did not become available in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-111", + "scenario": "scenarios/progression-support-triage.json", + "feature": 611, + "featureName": "Support triage", + "criterion": "611a", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: the support-link control did not become available in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-111", + "scenario": "scenarios/progression-support-triage.json", + "feature": 611, + "featureName": "Support triage", + "criterion": "611b", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: the support-link control did not become available in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-111", + "scenario": "scenarios/progression-support-triage.json", + "feature": 611, + "featureName": "Support triage", + "criterion": "611c", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: the support-link control did not become available in time" + } + ] + } +} diff --git a/tools/stack-bench/qualification-evidence/ecommerce-l3-43d01f644/postgres-mutation.json b/tools/stack-bench/qualification-evidence/ecommerce-l3-43d01f644/postgres-mutation.json new file mode 100644 index 00000000000..49ffe78f1f8 --- /dev/null +++ b/tools/stack-bench/qualification-evidence/ecommerce-l3-43d01f644/postgres-mutation.json @@ -0,0 +1,946 @@ +{ + "artifactSchemaVersion": 2, + "kind": "reference_qualification", + "id": "reference-live-postgres-20260916171515-31", + "attempt": { + "id": "reference-live-postgres-20260916171515-31", + "parentId": null + }, + "timestamps": { + "startedAt": "2026-09-16T17:15:15.445Z", + "completedAt": "2026-09-16T17:57:33.664Z" + }, + "identities": { + "engine": { + "id": "stack-bench", + "sha256": "31ffc8e48b22c397d10aa5ca2b6bc0680e9ae20fd8903bccc4d7db406a1478de" + }, + "recipe": { + "id": "ecommerce.progression-catalog", + "sha256": "11d743dd95a4671bdbb71c10f75b8405671f20a32c5312c9832c8ff9481e7ed5" + }, + "fixture": { + "id": "ecommerce-reference-postgres", + "sha256": "7904f54ad14206c2bd823e8bc0df555623bddabc40dc93313b6fb547396378c5" + }, + "calibration": { + "id": "ecommerce.dependency-l3-calibration", + "sha256": "578942627b3d6827609fb623361e1a672b4a602b65e0f1c501048b346438e954" + }, + "experiment": null, + "agentAdapter": null, + "stackAdapter": { + "id": "postgres", + "sha256": null + }, + "packs": [] + }, + "payload": { + "fixture": "ecommerce-reference-postgres", + "fixtureSha256": "7904f54ad14206c2bd823e8bc0df555623bddabc40dc93313b6fb547396378c5", + "requiredRepetitions": 1, + "isolation": "docker", + "runner": { + "schemaVersion": 1, + "mode": "appliance", + "platform": "linux", + "architecture": "x64", + "hostname": "docker-desktop", + "dockerEngineVersion": "29.6.2", + "dockerOs": "linux", + "dockerArchitecture": "x86_64", + "kernelVersion": "6.6.87.2-microsoft-standard-WSL2", + "cpuCount": 32, + "memoryBytes": 49232846848, + "containersRunning": 12, + "packageRegistry": "http://127.0.0.1:4873/" + }, + "qualificationScope": { + "checksSha256": "adc107253c217dc57e6b0648b083b5762f1358871f2764baad8cacfd3083eb10", + "executableSha256": "ec262b421294d4c6091eeb786c55a3eb83e7edf863675351e6986acb36db9e8e", + "kind": "mutation", + "mutationSha256": "299cef9445edebc73f063b1c985bf72cc6e561ba5318c172da6a555422ed76ca", + "recipe": { + "contentSha256": "11d743dd95a4671bdbb71c10f75b8405671f20a32c5312c9832c8ff9481e7ed5", + "id": "ecommerce.progression-catalog" + }, + "schemaVersion": 3, + "stack": { + "id": "postgres", + "reference": { + "id": "ecommerce-reference-postgres", + "sourceSha256": "7904f54ad14206c2bd823e8bc0df555623bddabc40dc93313b6fb547396378c5" + }, + "version": "1.6.0" + }, + "sha256": "fee1a11de9d24506805880f8a5db7647578ee001dc5bb35a5481a1435914359f" + }, + "mutationControl": true, + "runs": [ + { + "repetition": 1, + "output": "ecommerce-l3-11d743dd95a4-postgres-mutation.runs/r1-workers", + "durationMs": 2538134, + "processError": null, + "harnessSha256Before": "7aa0044000ff319fd5c8b95575d9636a8835ded1afea277d16c7871dd30eadf8", + "harnessSha256After": "7aa0044000ff319fd5c8b95575d9636a8835ded1afea277d16c7871dd30eadf8", + "ok": true, + "failures": [], + "runId": "reference-live-postgres-20260916171515-31", + "score": "180/180", + "imageId": "sha256:32ff9a9e519ba9d1af2fe72f24622caa8ca7a9f2baf2338c6b1e0435e6ac5455", + "criteria": 111, + "zeroPointCriteria": 0, + "fingerprint": "01676f87359c0bfc4b294128f48746ef655e9e4b61734439a2ea4b95dc34a605", + "outcome": "passed", + "packRuntime": { + "schemaVersion": 1, + "metric": "pack-check-wall-clock-sum-v1", + "packs": [ + { + "id": "ecommerce.feature.accounts", + "checkCount": 4, + "setupRuntimeMs": 1187, + "criterionRuntimeMs": 15251, + "measuredRuntimeMs": 16438, + "budget": { + "status": "bounded", + "maxRuntimeMs": 18000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.cart", + "checkCount": 1, + "setupRuntimeMs": 485, + "criterionRuntimeMs": 6051, + "measuredRuntimeMs": 6536, + "budget": { + "status": "bounded", + "maxRuntimeMs": 42000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.catalog-discovery", + "checkCount": 2, + "setupRuntimeMs": 0, + "criterionRuntimeMs": 1835, + "measuredRuntimeMs": 1835, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.catalog-items", + "checkCount": 1, + "setupRuntimeMs": 0, + "criterionRuntimeMs": 257, + "measuredRuntimeMs": 257, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.checkout", + "checkCount": 1, + "setupRuntimeMs": 485, + "criterionRuntimeMs": 6069, + "measuredRuntimeMs": 6554, + "budget": { + "status": "bounded", + "maxRuntimeMs": 42000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.purchasing", + "checkCount": 1, + "setupRuntimeMs": 337, + "criterionRuntimeMs": 1184, + "measuredRuntimeMs": 1521, + "budget": { + "status": "bounded", + "maxRuntimeMs": 24000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.reviews", + "checkCount": 1, + "setupRuntimeMs": 1731, + "criterionRuntimeMs": 383, + "measuredRuntimeMs": 2114, + "budget": { + "status": "bounded", + "maxRuntimeMs": 22000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.warehouse-admin", + "checkCount": 2, + "setupRuntimeMs": 1291, + "criterionRuntimeMs": 4322, + "measuredRuntimeMs": 5613, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.inventory-dashboard", + "checkCount": 1, + "setupRuntimeMs": 3414, + "criterionRuntimeMs": 7, + "measuredRuntimeMs": 3421, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.order-cancellation-features", + "checkCount": 2, + "setupRuntimeMs": 893, + "criterionRuntimeMs": 11228, + "measuredRuntimeMs": 12121, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.recommendations", + "checkCount": 1, + "setupRuntimeMs": 328, + "criterionRuntimeMs": 5172, + "measuredRuntimeMs": 5500, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.sales-dashboard", + "checkCount": 2, + "setupRuntimeMs": 2051, + "criterionRuntimeMs": 5026, + "measuredRuntimeMs": 7077, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.stock-transfers-features", + "checkCount": 1, + "setupRuntimeMs": 443, + "criterionRuntimeMs": 924, + "measuredRuntimeMs": 1367, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.deferred-access-specifications", + "checkCount": 1, + "setupRuntimeMs": 21014, + "criterionRuntimeMs": 4293, + "measuredRuntimeMs": 25307, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.deferred-durability-specifications", + "checkCount": 1, + "setupRuntimeMs": 126312, + "criterionRuntimeMs": 41137, + "measuredRuntimeMs": 167449, + "budget": { + "status": "bounded", + "maxRuntimeMs": 720000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.deferred-integrity-specifications", + "checkCount": 1, + "setupRuntimeMs": 42305, + "criterionRuntimeMs": 38438, + "measuredRuntimeMs": 80743, + "budget": { + "status": "bounded", + "maxRuntimeMs": 400000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.scheduled-restocks-features", + "checkCount": 3, + "setupRuntimeMs": 61825, + "criterionRuntimeMs": 71324, + "measuredRuntimeMs": 133149, + "budget": { + "status": "bounded", + "maxRuntimeMs": 150000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.server-time-specifications", + "checkCount": 1, + "setupRuntimeMs": 27409, + "criterionRuntimeMs": 112776, + "measuredRuntimeMs": 140185, + "budget": { + "status": "bounded", + "maxRuntimeMs": 300000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.cancellation-accounting-specifications", + "checkCount": 1, + "setupRuntimeMs": 605, + "criterionRuntimeMs": 8854, + "measuredRuntimeMs": 9459, + "budget": { + "status": "bounded", + "maxRuntimeMs": 24000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.catalog-management", + "checkCount": 2, + "setupRuntimeMs": 3413, + "criterionRuntimeMs": 26, + "measuredRuntimeMs": 3439, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.customer-profile", + "checkCount": 1, + "setupRuntimeMs": 506, + "criterionRuntimeMs": 5072, + "measuredRuntimeMs": 5578, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.faceted-search", + "checkCount": 2, + "setupRuntimeMs": 42719, + "criterionRuntimeMs": 25679, + "measuredRuntimeMs": 68398, + "budget": { + "status": "bounded", + "maxRuntimeMs": 141000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.fulfilment-queue", + "checkCount": 2, + "setupRuntimeMs": 1201, + "criterionRuntimeMs": 26670, + "measuredRuntimeMs": 27871, + "budget": { + "status": "bounded", + "maxRuntimeMs": 76000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.inventory-conservation-specifications", + "checkCount": 5, + "setupRuntimeMs": 2738, + "criterionRuntimeMs": 45450, + "measuredRuntimeMs": 48188, + "budget": { + "status": "bounded", + "maxRuntimeMs": 138000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.managed-support", + "checkCount": 1, + "setupRuntimeMs": 1113, + "criterionRuntimeMs": 6186, + "measuredRuntimeMs": 7299, + "budget": { + "status": "bounded", + "maxRuntimeMs": 55000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.notification-preferences", + "checkCount": 1, + "setupRuntimeMs": 691, + "criterionRuntimeMs": 5074, + "measuredRuntimeMs": 5765, + "budget": { + "status": "bounded", + "maxRuntimeMs": 40000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.operations-access-specifications", + "checkCount": 3, + "setupRuntimeMs": 9855, + "criterionRuntimeMs": 34174, + "measuredRuntimeMs": 44029, + "budget": { + "status": "bounded", + "maxRuntimeMs": 98000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.promotion-rules", + "checkCount": 1, + "setupRuntimeMs": 596, + "criterionRuntimeMs": 382, + "measuredRuntimeMs": 978, + "budget": { + "status": "bounded", + "maxRuntimeMs": 45000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.review-access-specifications", + "checkCount": 1, + "setupRuntimeMs": 4223, + "criterionRuntimeMs": 6813, + "measuredRuntimeMs": 11036, + "budget": { + "status": "bounded", + "maxRuntimeMs": 62000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.staff-access", + "checkCount": 1, + "setupRuntimeMs": 0, + "criterionRuntimeMs": 717, + "measuredRuntimeMs": 717, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.staff-roles", + "checkCount": 1, + "setupRuntimeMs": 698, + "criterionRuntimeMs": 29, + "measuredRuntimeMs": 727, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.stock-alerts", + "checkCount": 1, + "setupRuntimeMs": 3954, + "criterionRuntimeMs": 11127, + "measuredRuntimeMs": 15081, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.support-history", + "checkCount": 1, + "setupRuntimeMs": 793, + "criterionRuntimeMs": 1194, + "measuredRuntimeMs": 1987, + "budget": { + "status": "bounded", + "maxRuntimeMs": 50000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.support-intake", + "checkCount": 1, + "setupRuntimeMs": 0, + "criterionRuntimeMs": 419, + "measuredRuntimeMs": 419, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.support-triage", + "checkCount": 3, + "setupRuntimeMs": 823, + "criterionRuntimeMs": 10083, + "measuredRuntimeMs": 10906, + "budget": { + "status": "bounded", + "maxRuntimeMs": 45000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.access-control", + "checkCount": 21, + "setupRuntimeMs": 27413, + "criterionRuntimeMs": 212588, + "measuredRuntimeMs": 240001, + "budget": { + "status": "bounded", + "maxRuntimeMs": 464000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.concurrency-safety", + "checkCount": 6, + "setupRuntimeMs": 23643, + "criterionRuntimeMs": 46845, + "measuredRuntimeMs": 70488, + "budget": { + "status": "bounded", + "maxRuntimeMs": 125000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.external-data-sync", + "checkCount": 3, + "setupRuntimeMs": 630, + "criterionRuntimeMs": 28092, + "measuredRuntimeMs": 28722, + "budget": { + "status": "bounded", + "maxRuntimeMs": 105000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.live-state", + "checkCount": 11, + "setupRuntimeMs": 20210, + "criterionRuntimeMs": 6553, + "measuredRuntimeMs": 26763, + "budget": { + "status": "bounded", + "maxRuntimeMs": 184000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.search-ordering", + "checkCount": 1, + "setupRuntimeMs": 20920, + "criterionRuntimeMs": 5709, + "measuredRuntimeMs": 26629, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.state-durability", + "checkCount": 8, + "setupRuntimeMs": 4989, + "criterionRuntimeMs": 64383, + "measuredRuntimeMs": 69372, + "budget": { + "status": "bounded", + "maxRuntimeMs": 408000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.transactional-integrity", + "checkCount": 6, + "setupRuntimeMs": 23778, + "criterionRuntimeMs": 30813, + "measuredRuntimeMs": 54591, + "budget": { + "status": "bounded", + "maxRuntimeMs": 100000 + }, + "exceeded": false + } + ] + }, + "mutations": { + "caught": 108, + "total": 108 + }, + "baselineDurationMs": 1880957, + "baselineOutput": "ecommerce-l3-11d743dd95a4-postgres-mutation.runs/r1", + "baselineHarnessSha256Before": "7aa0044000ff319fd5c8b95575d9636a8835ded1afea277d16c7871dd30eadf8", + "baselineHarnessSha256After": "7aa0044000ff319fd5c8b95575d9636a8835ded1afea277d16c7871dd30eadf8", + "workers": [ + { + "index": 0, + "runIndex": 0, + "artifact": "ecommerce-l3-11d743dd95a4-postgres-mutation.runs/r1-workers/w1.json", + "mutationIds": [ + "staff-admin-access-survives-role-removal", + "signed-out-purchase-uses-default-account", + "direct-purchase-is-attributed-to-previous-account", + "oversell-no-row-lock", + "cancel-does-not-restore-stock-fresh-client", + "purchases-do-not-affect-best-sellers", + "staff-role-write-precedes-denial", + "progression-managed-support-is-not-shared", + "progression-stock-alerts-leak-across-accounts", + "progression-cart-line-does-not-increment", + "progression-concurrent-cart-line-does-not-increment", + "progression-cart-add-uses-another-account", + "low-stock-threshold-is-two-units", + "admin-sockets-do-not-join-admin-room" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-11d743dd95a4-postgres-mutation.runs/r1-workers/w1.stdout.log", + "stderr": "ecommerce-l3-11d743dd95a4-postgres-mutation.runs/r1-workers/w1.stderr.log" + } + }, + { + "index": 1, + "runIndex": 1, + "artifact": "ecommerce-l3-11d743dd95a4-postgres-mutation.runs/r1-workers/w2.json", + "mutationIds": [ + "shipping-counts-sale-twice", + "purchase-stock-change-is-not-broadcast--01-buying", + "direct-purchase-uses-constant-price", + "purchase-read-write-loses-concurrent-stock", + "cancel-restores-stock-but-keeps-pending-status", + "queue-warehouse-reports-west", + "progression-staff-can-assign-roles", + "progression-managed-support-leaks", + "progression-faceted-filter-ignores-category", + "progression-checkout-leaves-cart-lines", + "progression-concurrent-checkout-leaves-cart-lines", + "progression-customers-can-manage-scheduled-work", + "category-totals-render-as-session-deltas", + "transfer-overdraft-guard-skips-bulk-transfers" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-11d743dd95a4-postgres-mutation.runs/r1-workers/w2.stdout.log", + "stderr": "ecommerce-l3-11d743dd95a4-postgres-mutation.runs/r1-workers/w2.stderr.log" + } + }, + { + "index": 2, + "runIndex": 2, + "artifact": "ecommerce-l3-11d743dd95a4-postgres-mutation.runs/r1-workers/w3.json", + "mutationIds": [ + "signup-ui-does-not-enter-created-account", + "direct-purchase-order-total-is-offset", + "account-state-reload-discards-session", + "external-stock-polling-disabled", + "operator-authorization-allows-customer-transfer", + "transfer-overwrites-concurrent-purchase-with-stale-stock", + "progression-catalog-product-name-is-not-published", + "progression-promotion-discount-is-offset", + "active-search-uses-purchase-ranking", + "progression-cart-update-uses-wrong-room", + "progression-catalog-ranking-is-reversed", + "progression-restock-does-not-survive-restart", + "profile-summary-ignores-saved-address", + "transfer-does-not-publish-warehouse-totals" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-11d743dd95a4-postgres-mutation.runs/r1-workers/w3.stdout.log", + "stderr": "ecommerce-l3-11d743dd95a4-postgres-mutation.runs/r1-workers/w3.stderr.log" + } + }, + { + "index": 3, + "runIndex": 3, + "artifact": "ecommerce-l3-11d743dd95a4-postgres-mutation.runs/r1-workers/w4.json", + "mutationIds": [ + "duplicate-signup-authenticates-existing-account", + "reload-hydrates-an-empty-cart", + "offline-event-clears-account-state", + "server-restart-does-not-resynchronize-catalog", + "customer-can-ship-order-direct-1-1", + "progression-profile-address-is-discarded", + "progression-catalog-variants-are-discarded", + "progression-customer-can-create-promotions", + "progression-pagination-always-shows-first-page", + "progression-order-history-ignores-owner", + "progression-catalog-search-requires-exact-name", + "progression-restock-can-apply-more-than-once", + "support-first-reply-is-hidden", + "progression-support-history-anonymous-leak" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-11d743dd95a4-postgres-mutation.runs/r1-workers/w4.stdout.log", + "stderr": "ecommerce-l3-11d743dd95a4-postgres-mutation.runs/r1-workers/w4.stderr.log" + } + }, + { + "index": 4, + "runIndex": 4, + "artifact": "ecommerce-l3-11d743dd95a4-postgres-mutation.runs/r1-workers/w5.json", + "mutationIds": [ + "password-verification-is-inverted", + "signed-out-visitors-do-not-see-reviews", + "purchase-does-not-decrement-warehouse-stock", + "reconnect-does-not-send-current-catalog", + "customer-can-cancel-foreign-order-1-1", + "progression-profile-reads-another-account", + "progression-support-intake-is-disabled", + "progression-notification-preferences-do-not-save", + "progression-restock-countdown-is-fixed", + "progression-review-conflict-is-not-updated", + "progression-catalog-price-is-offset", + "restock-overwrites-instead-of-increments", + "notification-sync-flips-saved-toggle" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-11d743dd95a4-postgres-mutation.runs/r1-workers/w5.stdout.log", + "stderr": "ecommerce-l3-11d743dd95a4-postgres-mutation.runs/r1-workers/w5.stderr.log" + } + }, + { + "index": 5, + "runIndex": 5, + "artifact": "ecommerce-l3-11d743dd95a4-postgres-mutation.runs/r1-workers/w6.json", + "mutationIds": [ + "correct-signin-is-refused", + "review-average-update-is-not-broadcast", + "review-route-skips-purchase-eligibility", + "open-review-list-ignores-live-update", + "progression-customer-sees-fulfilment-content", + "progression-staff-tools-are-hidden", + "progression-support-triage-update-is-disabled", + "progression-notifications-leak-across-accounts", + "progression-due-restock-does-not-run", + "progression-revenue-double-counts-orders", + "progression-staff-sees-admin-navigation", + "direct-review-access-is-not-checked", + "staff-role-form-reverts-after-save" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-11d743dd95a4-postgres-mutation.runs/r1-workers/w6.stdout.log", + "stderr": "ecommerce-l3-11d743dd95a4-postgres-mutation.runs/r1-workers/w6.stderr.log" + } + }, + { + "index": 6, + "runIndex": 6, + "artifact": "ecommerce-l3-11d743dd95a4-postgres-mutation.runs/r1-workers/w7.json", + "mutationIds": [ + "reload-discards-session-identity", + "admin-warehouse-view-drops-one-location", + "only-shipped-orders-earn-review-eligibility", + "open-review-list-renders-each-review-twice", + "transfer-debits-source-without-crediting-existing-destination", + "progression-customer-sees-staff-tools", + "progression-support-history-is-not-persisted", + "stock-alert-delivery-is-suppressed", + "progression-cancelled-restock-still-runs", + "progression-cancelled-orders-remain-in-revenue", + "progression-staff-can-restock-directly", + "support-history-rows-are-hidden", + "purchase-does-not-broadcast-fulfilment-queue" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-11d743dd95a4-postgres-mutation.runs/r1-workers/w7.stdout.log", + "stderr": "ecommerce-l3-11d743dd95a4-postgres-mutation.runs/r1-workers/w7.stderr.log" + } + }, + { + "index": 7, + "runIndex": 7, + "artifact": "ecommerce-l3-11d743dd95a4-postgres-mutation.runs/r1-workers/w8.json", + "mutationIds": [ + "purchase-does-not-broadcast-ranking", + "unauthenticated-direct-purchase-uses-default-account", + "cart-update-accepts-negative-quantity", + "cancel-does-not-restore-stock-feature", + "recommendations-ignore-pending-purchases", + "progression-staff-role-is-lost-on-restart", + "progression-support-history-leaks", + "stock-alert-is-sent-after-every-restock", + "progression-restart-timer-never-runs", + "progression-shipping-keeps-order-pending", + "progression-restock-adds-wrong-quantity", + "authorized-restock-does-not-change-stock", + "admin-state-change-is-not-broadcast" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-11d743dd95a4-postgres-mutation.runs/r1-workers/w8.stdout.log", + "stderr": "ecommerce-l3-11d743dd95a4-postgres-mutation.runs/r1-workers/w8.stderr.log" + } + } + ] + } + ], + "stable": true, + "sameImage": true, + "sameHarness": true, + "harnessSha256": "7aa0044000ff319fd5c8b95575d9636a8835ded1afea277d16c7871dd30eadf8", + "qualifiedCheckKeys": [ + "ecommerce.feature.accounts.accounts.1a", + "ecommerce.feature.accounts.accounts.1b", + "ecommerce.feature.accounts.accounts.1c", + "ecommerce.feature.accounts.accounts.1d", + "ecommerce.feature.cart-checkout.cart.4a", + "ecommerce.feature.cart-checkout.cart.4d", + "ecommerce.feature.catalog.catalog-ranking.2b", + "ecommerce.feature.catalog.catalog-search.2d", + "ecommerce.feature.catalog.catalog-values.2a", + "ecommerce.feature.purchasing.purchase-order.3c", + "ecommerce.feature.reviews.reviews.6a", + "ecommerce.feature.warehouse-admin.admin-write.103a", + "ecommerce.feature.warehouse-admin.warehouse-view.7b", + "ecommerce.inventory-operations.operational-views.5c", + "ecommerce.inventory-operations.operational-views.5d", + "ecommerce.inventory-operations.operational-views.5e", + "ecommerce.inventory-operations.operational-views.5f", + "ecommerce.inventory-operations.shipping-accounting.202e", + "ecommerce.inventory-operations.stock-conservation.202a", + "ecommerce.inventory-operations.stock-conservation.202b", + "ecommerce.inventory-operations.stock-conservation.202c", + "ecommerce.inventory-operations.stock-conservation.202d", + "ecommerce.inventory-operations.warehouse-transfer.2a", + "ecommerce.l3.deferred-access.scheduled-work-access.317a", + "ecommerce.l3.deferred-durability.restart-survival.311a", + "ecommerce.l3.deferred-integrity.exactly-once.311a", + "ecommerce.l3.scheduled-restocks.scheduled-restocks.302a", + "ecommerce.l3.scheduled-restocks.scheduled-restocks.305a", + "ecommerce.l3.scheduled-restocks.scheduled-restocks.306a", + "ecommerce.l3.server-time.server-time.312a", + "ecommerce.operations-access.fulfilment-queue.1b", + "ecommerce.operations-access.fulfilment-queue.1c", + "ecommerce.operations-access.operator-authorization.201a", + "ecommerce.operations-access.operator-authorization.201c", + "ecommerce.operations-access.order-owner.204a", + "ecommerce.progression.catalog-management.catalog-management.622a", + "ecommerce.progression.catalog-management.catalog-management.622b", + "ecommerce.progression.customer-profile.customer-profile.620c", + "ecommerce.progression.faceted-search.faceted-search.401a", + "ecommerce.progression.faceted-search.faceted-search.402a", + "ecommerce.progression.managed-support.managed-support.613c", + "ecommerce.progression.notification-preferences.notification-preferences.630c", + "ecommerce.progression.promotion-rules.promotion-rule-values.620a", + "ecommerce.progression.review-access-specifications.review-eligibility-direct.618a", + "ecommerce.progression.staff-access.staff-access.601a", + "ecommerce.progression.staff-roles.staff-roles.621c", + "ecommerce.progression.stock-alerts.stock-alert-delivery.631c", + "ecommerce.progression.support-history.support-history.612c", + "ecommerce.progression.support-intake.support-intake.610a", + "ecommerce.progression.support-triage.support-assignment.611a", + "ecommerce.progression.support-triage.support-priority.611b", + "ecommerce.progression.support-triage.support-status.611c", + "ecommerce.returns-pricing.cancellation-and-return.3a", + "ecommerce.returns-pricing.cancellation-and-return.3b", + "ecommerce.returns-pricing.refund-accounting.203a", + "ecommerce.spec.access-control.cart-boundary.109a", + "ecommerce.spec.access-control.cart-boundary.109b", + "ecommerce.spec.access-control.customer-profile-privacy.620b", + "ecommerce.spec.access-control.fulfilment-area-boundary.1d", + "ecommerce.spec.access-control.managed-support-privacy.613b", + "ecommerce.spec.access-control.notification-preferences-privacy.630b", + "ecommerce.spec.access-control.order-ownership.106a", + "ecommerce.spec.access-control.promotion-management-boundary.620b", + "ecommerce.spec.access-control.purchase-attribution.102a", + "ecommerce.spec.access-control.purchase-session.101a", + "ecommerce.spec.access-control.review-eligibility.108a", + "ecommerce.spec.access-control.review-eligibility.108b", + "ecommerce.spec.access-control.signed-out-purchase.3a", + "ecommerce.spec.access-control.staff-area-boundary.601b", + "ecommerce.spec.access-control.staff-role-boundary.621b", + "ecommerce.spec.access-control.staff-role-revocation.621d", + "ecommerce.spec.access-control.stock-alert-privacy.631b", + "ecommerce.spec.access-control.support-history-logout.612d", + "ecommerce.spec.access-control.support-history-privacy.612b", + "ecommerce.spec.access-control.warehouse-area-boundary.7a", + "ecommerce.spec.access-control.warehouse-write-boundary.103b", + "ecommerce.spec.concurrency-safety.duplicate-checkout.203a", + "ecommerce.spec.concurrency-safety.duplicate-checkout.203b", + "ecommerce.spec.concurrency-safety.last-unit.201a", + "ecommerce.spec.concurrency-safety.last-unit.201b", + "ecommerce.spec.concurrency-safety.last-unit.201c", + "ecommerce.spec.concurrency-safety.restock-race.202a", + "ecommerce.spec.external-data-sync.external-stock.901a", + "ecommerce.spec.external-data-sync.external-stock.901c", + "ecommerce.spec.external-data-sync.external-stock.901d", + "ecommerce.spec.live-state.fulfilment-queue.1a", + "ecommerce.spec.live-state.inventory-dashboard.5a", + "ecommerce.spec.live-state.managed-support.613a", + "ecommerce.spec.live-state.open-list.902a", + "ecommerce.spec.live-state.purchase-stock.3b", + "ecommerce.spec.live-state.ranking.2c", + "ecommerce.spec.live-state.rating.6c", + "ecommerce.spec.live-state.sales-dashboard.5b", + "ecommerce.spec.live-state.shared-cart.4c", + "ecommerce.spec.live-state.stock-transfers.2b", + "ecommerce.spec.live-state.warehouse-stock.7c", + "ecommerce.spec.search-ordering.search-ordering.402b", + "ecommerce.spec.state-durability.account-state-recovery.105a", + "ecommerce.spec.state-durability.account-state-recovery.105b", + "ecommerce.spec.state-durability.cart-reload.4b", + "ecommerce.spec.state-durability.customer-profile-reload.620a", + "ecommerce.spec.state-durability.notification-preferences-reload.630a", + "ecommerce.spec.state-durability.session-reload.1e", + "ecommerce.spec.state-durability.staff-role-reload.621a", + "ecommerce.spec.state-durability.support-history-reload.612a", + "ecommerce.spec.transactional-integrity.books-balance.107a", + "ecommerce.spec.transactional-integrity.books-balance.107b", + "ecommerce.spec.transactional-integrity.server-price.104a", + "ecommerce.spec.transactional-integrity.stock-alert-deduplication.631a", + "ecommerce.spec.transactional-integrity.stock-transfer-overdraw.2c", + "ecommerce.spec.transactional-integrity.unique-review.6b" + ], + "featureCatalog": { + "contentSha256": "863e2a2b09f7b00d1b9755607347364e3ad9013d0ceea58ceca93b1f933f3e45", + "id": "ecommerce.questlines" + }, + "diagnostic": false, + "ok": true + } +} diff --git a/tools/stack-bench/qualification-evidence/ecommerce-l3-43d01f644/postgres-reference.json b/tools/stack-bench/qualification-evidence/ecommerce-l3-43d01f644/postgres-reference.json new file mode 100644 index 00000000000..4e6f47a5054 --- /dev/null +++ b/tools/stack-bench/qualification-evidence/ecommerce-l3-43d01f644/postgres-reference.json @@ -0,0 +1,733 @@ +{ + "artifactSchemaVersion": 2, + "kind": "reference_qualification", + "id": "reference-live-postgres-20260916171515-31-reference", + "attempt": { + "id": "reference-live-postgres-20260916171515-31-reference", + "parentId": null + }, + "timestamps": { + "startedAt": "2026-09-16T17:15:15.445Z", + "completedAt": "2026-09-16T17:57:33.666Z" + }, + "identities": { + "engine": { + "id": "stack-bench", + "sha256": "31ffc8e48b22c397d10aa5ca2b6bc0680e9ae20fd8903bccc4d7db406a1478de" + }, + "recipe": { + "id": "ecommerce.progression-catalog", + "sha256": "11d743dd95a4671bdbb71c10f75b8405671f20a32c5312c9832c8ff9481e7ed5" + }, + "fixture": { + "id": "ecommerce-reference-postgres", + "sha256": "7904f54ad14206c2bd823e8bc0df555623bddabc40dc93313b6fb547396378c5" + }, + "calibration": { + "id": "ecommerce.dependency-l3-calibration", + "sha256": "578942627b3d6827609fb623361e1a672b4a602b65e0f1c501048b346438e954" + }, + "experiment": null, + "agentAdapter": null, + "stackAdapter": { + "id": "postgres", + "sha256": null + }, + "packs": [] + }, + "payload": { + "fixture": "ecommerce-reference-postgres", + "fixtureSha256": "7904f54ad14206c2bd823e8bc0df555623bddabc40dc93313b6fb547396378c5", + "requiredRepetitions": 1, + "isolation": "docker", + "runner": { + "schemaVersion": 1, + "mode": "appliance", + "platform": "linux", + "architecture": "x64", + "hostname": "docker-desktop", + "dockerEngineVersion": "29.6.2", + "dockerOs": "linux", + "dockerArchitecture": "x86_64", + "kernelVersion": "6.6.87.2-microsoft-standard-WSL2", + "cpuCount": 32, + "memoryBytes": 49232846848, + "containersRunning": 12, + "packageRegistry": "http://127.0.0.1:4873/" + }, + "qualificationScope": { + "checksSha256": "adc107253c217dc57e6b0648b083b5762f1358871f2764baad8cacfd3083eb10", + "executableSha256": "ec262b421294d4c6091eeb786c55a3eb83e7edf863675351e6986acb36db9e8e", + "kind": "reference", + "mutationSha256": null, + "recipe": { + "contentSha256": "11d743dd95a4671bdbb71c10f75b8405671f20a32c5312c9832c8ff9481e7ed5", + "id": "ecommerce.progression-catalog" + }, + "schemaVersion": 3, + "stack": { + "id": "postgres", + "reference": { + "id": "ecommerce-reference-postgres", + "sourceSha256": "7904f54ad14206c2bd823e8bc0df555623bddabc40dc93313b6fb547396378c5" + }, + "version": "1.6.0" + }, + "sha256": "b6086025d501a092a8b79926fa71c1649480d96945327770f2b34b1fd5212374" + }, + "mutationControl": false, + "runs": [ + { + "repetition": 1, + "output": "ecommerce-l3-11d743dd95a4-postgres-mutation.runs/r1", + "durationMs": 1880957, + "processError": null, + "harnessSha256Before": "7aa0044000ff319fd5c8b95575d9636a8835ded1afea277d16c7871dd30eadf8", + "harnessSha256After": "7aa0044000ff319fd5c8b95575d9636a8835ded1afea277d16c7871dd30eadf8", + "ok": true, + "failures": [], + "runId": "ecommerce-postgres-run0-20260916171516-2ee9da99", + "score": "180/180", + "imageId": "sha256:32ff9a9e519ba9d1af2fe72f24622caa8ca7a9f2baf2338c6b1e0435e6ac5455", + "criteria": 111, + "zeroPointCriteria": 0, + "fingerprint": "01676f87359c0bfc4b294128f48746ef655e9e4b61734439a2ea4b95dc34a605", + "outcome": "passed", + "packRuntime": { + "schemaVersion": 1, + "metric": "pack-check-wall-clock-sum-v1", + "packs": [ + { + "id": "ecommerce.feature.accounts", + "checkCount": 4, + "setupRuntimeMs": 1187, + "criterionRuntimeMs": 15251, + "measuredRuntimeMs": 16438, + "budget": { + "status": "bounded", + "maxRuntimeMs": 18000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.cart", + "checkCount": 1, + "setupRuntimeMs": 485, + "criterionRuntimeMs": 6051, + "measuredRuntimeMs": 6536, + "budget": { + "status": "bounded", + "maxRuntimeMs": 42000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.catalog-discovery", + "checkCount": 2, + "setupRuntimeMs": 0, + "criterionRuntimeMs": 1835, + "measuredRuntimeMs": 1835, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.catalog-items", + "checkCount": 1, + "setupRuntimeMs": 0, + "criterionRuntimeMs": 257, + "measuredRuntimeMs": 257, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.checkout", + "checkCount": 1, + "setupRuntimeMs": 485, + "criterionRuntimeMs": 6069, + "measuredRuntimeMs": 6554, + "budget": { + "status": "bounded", + "maxRuntimeMs": 42000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.purchasing", + "checkCount": 1, + "setupRuntimeMs": 337, + "criterionRuntimeMs": 1184, + "measuredRuntimeMs": 1521, + "budget": { + "status": "bounded", + "maxRuntimeMs": 24000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.reviews", + "checkCount": 1, + "setupRuntimeMs": 1731, + "criterionRuntimeMs": 383, + "measuredRuntimeMs": 2114, + "budget": { + "status": "bounded", + "maxRuntimeMs": 22000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.warehouse-admin", + "checkCount": 2, + "setupRuntimeMs": 1291, + "criterionRuntimeMs": 4322, + "measuredRuntimeMs": 5613, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.inventory-dashboard", + "checkCount": 1, + "setupRuntimeMs": 3414, + "criterionRuntimeMs": 7, + "measuredRuntimeMs": 3421, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.order-cancellation-features", + "checkCount": 2, + "setupRuntimeMs": 893, + "criterionRuntimeMs": 11228, + "measuredRuntimeMs": 12121, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.recommendations", + "checkCount": 1, + "setupRuntimeMs": 328, + "criterionRuntimeMs": 5172, + "measuredRuntimeMs": 5500, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.sales-dashboard", + "checkCount": 2, + "setupRuntimeMs": 2051, + "criterionRuntimeMs": 5026, + "measuredRuntimeMs": 7077, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.stock-transfers-features", + "checkCount": 1, + "setupRuntimeMs": 443, + "criterionRuntimeMs": 924, + "measuredRuntimeMs": 1367, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.deferred-access-specifications", + "checkCount": 1, + "setupRuntimeMs": 21014, + "criterionRuntimeMs": 4293, + "measuredRuntimeMs": 25307, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.deferred-durability-specifications", + "checkCount": 1, + "setupRuntimeMs": 126312, + "criterionRuntimeMs": 41137, + "measuredRuntimeMs": 167449, + "budget": { + "status": "bounded", + "maxRuntimeMs": 720000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.deferred-integrity-specifications", + "checkCount": 1, + "setupRuntimeMs": 42305, + "criterionRuntimeMs": 38438, + "measuredRuntimeMs": 80743, + "budget": { + "status": "bounded", + "maxRuntimeMs": 400000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.scheduled-restocks-features", + "checkCount": 3, + "setupRuntimeMs": 61825, + "criterionRuntimeMs": 71324, + "measuredRuntimeMs": 133149, + "budget": { + "status": "bounded", + "maxRuntimeMs": 150000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.server-time-specifications", + "checkCount": 1, + "setupRuntimeMs": 27409, + "criterionRuntimeMs": 112776, + "measuredRuntimeMs": 140185, + "budget": { + "status": "bounded", + "maxRuntimeMs": 300000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.cancellation-accounting-specifications", + "checkCount": 1, + "setupRuntimeMs": 605, + "criterionRuntimeMs": 8854, + "measuredRuntimeMs": 9459, + "budget": { + "status": "bounded", + "maxRuntimeMs": 24000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.catalog-management", + "checkCount": 2, + "setupRuntimeMs": 3413, + "criterionRuntimeMs": 26, + "measuredRuntimeMs": 3439, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.customer-profile", + "checkCount": 1, + "setupRuntimeMs": 506, + "criterionRuntimeMs": 5072, + "measuredRuntimeMs": 5578, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.faceted-search", + "checkCount": 2, + "setupRuntimeMs": 42719, + "criterionRuntimeMs": 25679, + "measuredRuntimeMs": 68398, + "budget": { + "status": "bounded", + "maxRuntimeMs": 141000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.fulfilment-queue", + "checkCount": 2, + "setupRuntimeMs": 1201, + "criterionRuntimeMs": 26670, + "measuredRuntimeMs": 27871, + "budget": { + "status": "bounded", + "maxRuntimeMs": 76000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.inventory-conservation-specifications", + "checkCount": 5, + "setupRuntimeMs": 2738, + "criterionRuntimeMs": 45450, + "measuredRuntimeMs": 48188, + "budget": { + "status": "bounded", + "maxRuntimeMs": 138000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.managed-support", + "checkCount": 1, + "setupRuntimeMs": 1113, + "criterionRuntimeMs": 6186, + "measuredRuntimeMs": 7299, + "budget": { + "status": "bounded", + "maxRuntimeMs": 55000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.notification-preferences", + "checkCount": 1, + "setupRuntimeMs": 691, + "criterionRuntimeMs": 5074, + "measuredRuntimeMs": 5765, + "budget": { + "status": "bounded", + "maxRuntimeMs": 40000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.operations-access-specifications", + "checkCount": 3, + "setupRuntimeMs": 9855, + "criterionRuntimeMs": 34174, + "measuredRuntimeMs": 44029, + "budget": { + "status": "bounded", + "maxRuntimeMs": 98000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.promotion-rules", + "checkCount": 1, + "setupRuntimeMs": 596, + "criterionRuntimeMs": 382, + "measuredRuntimeMs": 978, + "budget": { + "status": "bounded", + "maxRuntimeMs": 45000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.review-access-specifications", + "checkCount": 1, + "setupRuntimeMs": 4223, + "criterionRuntimeMs": 6813, + "measuredRuntimeMs": 11036, + "budget": { + "status": "bounded", + "maxRuntimeMs": 62000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.staff-access", + "checkCount": 1, + "setupRuntimeMs": 0, + "criterionRuntimeMs": 717, + "measuredRuntimeMs": 717, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.staff-roles", + "checkCount": 1, + "setupRuntimeMs": 698, + "criterionRuntimeMs": 29, + "measuredRuntimeMs": 727, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.stock-alerts", + "checkCount": 1, + "setupRuntimeMs": 3954, + "criterionRuntimeMs": 11127, + "measuredRuntimeMs": 15081, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.support-history", + "checkCount": 1, + "setupRuntimeMs": 793, + "criterionRuntimeMs": 1194, + "measuredRuntimeMs": 1987, + "budget": { + "status": "bounded", + "maxRuntimeMs": 50000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.support-intake", + "checkCount": 1, + "setupRuntimeMs": 0, + "criterionRuntimeMs": 419, + "measuredRuntimeMs": 419, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.support-triage", + "checkCount": 3, + "setupRuntimeMs": 823, + "criterionRuntimeMs": 10083, + "measuredRuntimeMs": 10906, + "budget": { + "status": "bounded", + "maxRuntimeMs": 45000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.access-control", + "checkCount": 21, + "setupRuntimeMs": 27413, + "criterionRuntimeMs": 212588, + "measuredRuntimeMs": 240001, + "budget": { + "status": "bounded", + "maxRuntimeMs": 464000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.concurrency-safety", + "checkCount": 6, + "setupRuntimeMs": 23643, + "criterionRuntimeMs": 46845, + "measuredRuntimeMs": 70488, + "budget": { + "status": "bounded", + "maxRuntimeMs": 125000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.external-data-sync", + "checkCount": 3, + "setupRuntimeMs": 630, + "criterionRuntimeMs": 28092, + "measuredRuntimeMs": 28722, + "budget": { + "status": "bounded", + "maxRuntimeMs": 105000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.live-state", + "checkCount": 11, + "setupRuntimeMs": 20210, + "criterionRuntimeMs": 6553, + "measuredRuntimeMs": 26763, + "budget": { + "status": "bounded", + "maxRuntimeMs": 184000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.search-ordering", + "checkCount": 1, + "setupRuntimeMs": 20920, + "criterionRuntimeMs": 5709, + "measuredRuntimeMs": 26629, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.state-durability", + "checkCount": 8, + "setupRuntimeMs": 4989, + "criterionRuntimeMs": 64383, + "measuredRuntimeMs": 69372, + "budget": { + "status": "bounded", + "maxRuntimeMs": 408000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.transactional-integrity", + "checkCount": 6, + "setupRuntimeMs": 23778, + "criterionRuntimeMs": 30813, + "measuredRuntimeMs": 54591, + "budget": { + "status": "bounded", + "maxRuntimeMs": 100000 + }, + "exceeded": false + } + ] + }, + "mutations": null + } + ], + "stable": true, + "sameImage": true, + "sameHarness": true, + "harnessSha256": "7aa0044000ff319fd5c8b95575d9636a8835ded1afea277d16c7871dd30eadf8", + "qualifiedCheckKeys": [ + "ecommerce.feature.accounts.accounts.1a", + "ecommerce.feature.accounts.accounts.1b", + "ecommerce.feature.accounts.accounts.1c", + "ecommerce.feature.accounts.accounts.1d", + "ecommerce.feature.cart-checkout.cart.4a", + "ecommerce.feature.cart-checkout.cart.4d", + "ecommerce.feature.catalog.catalog-ranking.2b", + "ecommerce.feature.catalog.catalog-search.2d", + "ecommerce.feature.catalog.catalog-values.2a", + "ecommerce.feature.purchasing.purchase-order.3c", + "ecommerce.feature.reviews.reviews.6a", + "ecommerce.feature.warehouse-admin.admin-write.103a", + "ecommerce.feature.warehouse-admin.warehouse-view.7b", + "ecommerce.inventory-operations.operational-views.5c", + "ecommerce.inventory-operations.operational-views.5d", + "ecommerce.inventory-operations.operational-views.5e", + "ecommerce.inventory-operations.operational-views.5f", + "ecommerce.inventory-operations.shipping-accounting.202e", + "ecommerce.inventory-operations.stock-conservation.202a", + "ecommerce.inventory-operations.stock-conservation.202b", + "ecommerce.inventory-operations.stock-conservation.202c", + "ecommerce.inventory-operations.stock-conservation.202d", + "ecommerce.inventory-operations.warehouse-transfer.2a", + "ecommerce.l3.deferred-access.scheduled-work-access.317a", + "ecommerce.l3.deferred-durability.restart-survival.311a", + "ecommerce.l3.deferred-integrity.exactly-once.311a", + "ecommerce.l3.scheduled-restocks.scheduled-restocks.302a", + "ecommerce.l3.scheduled-restocks.scheduled-restocks.305a", + "ecommerce.l3.scheduled-restocks.scheduled-restocks.306a", + "ecommerce.l3.server-time.server-time.312a", + "ecommerce.operations-access.fulfilment-queue.1b", + "ecommerce.operations-access.fulfilment-queue.1c", + "ecommerce.operations-access.operator-authorization.201a", + "ecommerce.operations-access.operator-authorization.201c", + "ecommerce.operations-access.order-owner.204a", + "ecommerce.progression.catalog-management.catalog-management.622a", + "ecommerce.progression.catalog-management.catalog-management.622b", + "ecommerce.progression.customer-profile.customer-profile.620c", + "ecommerce.progression.faceted-search.faceted-search.401a", + "ecommerce.progression.faceted-search.faceted-search.402a", + "ecommerce.progression.managed-support.managed-support.613c", + "ecommerce.progression.notification-preferences.notification-preferences.630c", + "ecommerce.progression.promotion-rules.promotion-rule-values.620a", + "ecommerce.progression.review-access-specifications.review-eligibility-direct.618a", + "ecommerce.progression.staff-access.staff-access.601a", + "ecommerce.progression.staff-roles.staff-roles.621c", + "ecommerce.progression.stock-alerts.stock-alert-delivery.631c", + "ecommerce.progression.support-history.support-history.612c", + "ecommerce.progression.support-intake.support-intake.610a", + "ecommerce.progression.support-triage.support-assignment.611a", + "ecommerce.progression.support-triage.support-priority.611b", + "ecommerce.progression.support-triage.support-status.611c", + "ecommerce.returns-pricing.cancellation-and-return.3a", + "ecommerce.returns-pricing.cancellation-and-return.3b", + "ecommerce.returns-pricing.refund-accounting.203a", + "ecommerce.spec.access-control.cart-boundary.109a", + "ecommerce.spec.access-control.cart-boundary.109b", + "ecommerce.spec.access-control.customer-profile-privacy.620b", + "ecommerce.spec.access-control.fulfilment-area-boundary.1d", + "ecommerce.spec.access-control.managed-support-privacy.613b", + "ecommerce.spec.access-control.notification-preferences-privacy.630b", + "ecommerce.spec.access-control.order-ownership.106a", + "ecommerce.spec.access-control.promotion-management-boundary.620b", + "ecommerce.spec.access-control.purchase-attribution.102a", + "ecommerce.spec.access-control.purchase-session.101a", + "ecommerce.spec.access-control.review-eligibility.108a", + "ecommerce.spec.access-control.review-eligibility.108b", + "ecommerce.spec.access-control.signed-out-purchase.3a", + "ecommerce.spec.access-control.staff-area-boundary.601b", + "ecommerce.spec.access-control.staff-role-boundary.621b", + "ecommerce.spec.access-control.staff-role-revocation.621d", + "ecommerce.spec.access-control.stock-alert-privacy.631b", + "ecommerce.spec.access-control.support-history-logout.612d", + "ecommerce.spec.access-control.support-history-privacy.612b", + "ecommerce.spec.access-control.warehouse-area-boundary.7a", + "ecommerce.spec.access-control.warehouse-write-boundary.103b", + "ecommerce.spec.concurrency-safety.duplicate-checkout.203a", + "ecommerce.spec.concurrency-safety.duplicate-checkout.203b", + "ecommerce.spec.concurrency-safety.last-unit.201a", + "ecommerce.spec.concurrency-safety.last-unit.201b", + "ecommerce.spec.concurrency-safety.last-unit.201c", + "ecommerce.spec.concurrency-safety.restock-race.202a", + "ecommerce.spec.external-data-sync.external-stock.901a", + "ecommerce.spec.external-data-sync.external-stock.901c", + "ecommerce.spec.external-data-sync.external-stock.901d", + "ecommerce.spec.live-state.fulfilment-queue.1a", + "ecommerce.spec.live-state.inventory-dashboard.5a", + "ecommerce.spec.live-state.managed-support.613a", + "ecommerce.spec.live-state.open-list.902a", + "ecommerce.spec.live-state.purchase-stock.3b", + "ecommerce.spec.live-state.ranking.2c", + "ecommerce.spec.live-state.rating.6c", + "ecommerce.spec.live-state.sales-dashboard.5b", + "ecommerce.spec.live-state.shared-cart.4c", + "ecommerce.spec.live-state.stock-transfers.2b", + "ecommerce.spec.live-state.warehouse-stock.7c", + "ecommerce.spec.search-ordering.search-ordering.402b", + "ecommerce.spec.state-durability.account-state-recovery.105a", + "ecommerce.spec.state-durability.account-state-recovery.105b", + "ecommerce.spec.state-durability.cart-reload.4b", + "ecommerce.spec.state-durability.customer-profile-reload.620a", + "ecommerce.spec.state-durability.notification-preferences-reload.630a", + "ecommerce.spec.state-durability.session-reload.1e", + "ecommerce.spec.state-durability.staff-role-reload.621a", + "ecommerce.spec.state-durability.support-history-reload.612a", + "ecommerce.spec.transactional-integrity.books-balance.107a", + "ecommerce.spec.transactional-integrity.books-balance.107b", + "ecommerce.spec.transactional-integrity.server-price.104a", + "ecommerce.spec.transactional-integrity.stock-alert-deduplication.631a", + "ecommerce.spec.transactional-integrity.stock-transfer-overdraw.2c", + "ecommerce.spec.transactional-integrity.unique-review.6b" + ], + "featureCatalog": { + "contentSha256": "863e2a2b09f7b00d1b9755607347364e3ad9013d0ceea58ceca93b1f933f3e45", + "id": "ecommerce.questlines" + }, + "diagnostic": false, + "ok": true + } +} diff --git a/tools/stack-bench/qualification-evidence/ecommerce-l3-43d01f644/spacetime-mutation.json b/tools/stack-bench/qualification-evidence/ecommerce-l3-43d01f644/spacetime-mutation.json new file mode 100644 index 00000000000..6913b10d529 --- /dev/null +++ b/tools/stack-bench/qualification-evidence/ecommerce-l3-43d01f644/spacetime-mutation.json @@ -0,0 +1,951 @@ +{ + "artifactSchemaVersion": 2, + "kind": "reference_qualification", + "id": "reference-live-spacetime-20260916171515-31", + "attempt": { + "id": "reference-live-spacetime-20260916171515-31", + "parentId": null + }, + "timestamps": { + "startedAt": "2026-09-16T17:15:15.850Z", + "completedAt": "2026-09-16T18:07:26.983Z" + }, + "identities": { + "engine": { + "id": "stack-bench", + "sha256": "31ffc8e48b22c397d10aa5ca2b6bc0680e9ae20fd8903bccc4d7db406a1478de" + }, + "recipe": { + "id": "ecommerce.progression-catalog", + "sha256": "11d743dd95a4671bdbb71c10f75b8405671f20a32c5312c9832c8ff9481e7ed5" + }, + "fixture": { + "id": "ecommerce-reference-spacetime", + "sha256": "825d5666db0f2082a217d3b5d9aba0178054a014224c9d2ab8ae91cf8112af3f" + }, + "calibration": { + "id": "ecommerce.dependency-l3-calibration", + "sha256": "578942627b3d6827609fb623361e1a672b4a602b65e0f1c501048b346438e954" + }, + "experiment": null, + "agentAdapter": null, + "stackAdapter": { + "id": "spacetime", + "sha256": null + }, + "packs": [] + }, + "payload": { + "fixture": "ecommerce-reference-spacetime", + "fixtureSha256": "825d5666db0f2082a217d3b5d9aba0178054a014224c9d2ab8ae91cf8112af3f", + "requiredRepetitions": 1, + "isolation": "docker", + "runner": { + "schemaVersion": 1, + "mode": "appliance", + "platform": "linux", + "architecture": "x64", + "hostname": "docker-desktop", + "dockerEngineVersion": "29.6.2", + "dockerOs": "linux", + "dockerArchitecture": "x86_64", + "kernelVersion": "6.6.87.2-microsoft-standard-WSL2", + "cpuCount": 32, + "memoryBytes": 49232846848, + "containersRunning": 12, + "packageRegistry": "http://127.0.0.1:4873/" + }, + "qualificationScope": { + "checksSha256": "adc107253c217dc57e6b0648b083b5762f1358871f2764baad8cacfd3083eb10", + "executableSha256": "2d142aa52b18470145d996dba803dd5a5d14065fcf4f78ae8f0cfc38cb884cd5", + "kind": "mutation", + "mutationSha256": "a961f8c81dcd306ea7a8ea7e86a33afc9c21142fe1a28c94a10def9056e01c1b", + "recipe": { + "contentSha256": "11d743dd95a4671bdbb71c10f75b8405671f20a32c5312c9832c8ff9481e7ed5", + "id": "ecommerce.progression-catalog" + }, + "schemaVersion": 3, + "stack": { + "id": "spacetime", + "reference": { + "id": "ecommerce-reference-spacetime", + "sourceSha256": "825d5666db0f2082a217d3b5d9aba0178054a014224c9d2ab8ae91cf8112af3f" + }, + "version": "1.4.0" + }, + "sha256": "3e50748c95203257a2a3c19795225310c92302c7e999f4b69ecb55c65ff1c8d1" + }, + "mutationControl": true, + "runs": [ + { + "repetition": 1, + "output": "ecommerce-l3-11d743dd95a4-spacetime-mutation.runs/r1-workers", + "durationMs": 3131059, + "processError": null, + "harnessSha256Before": "7aa0044000ff319fd5c8b95575d9636a8835ded1afea277d16c7871dd30eadf8", + "harnessSha256After": "7aa0044000ff319fd5c8b95575d9636a8835ded1afea277d16c7871dd30eadf8", + "ok": true, + "failures": [], + "runId": "reference-live-spacetime-20260916171515-31", + "score": "180/180", + "imageId": "sha256:32ff9a9e519ba9d1af2fe72f24622caa8ca7a9f2baf2338c6b1e0435e6ac5455", + "criteria": 111, + "zeroPointCriteria": 0, + "fingerprint": "01676f87359c0bfc4b294128f48746ef655e9e4b61734439a2ea4b95dc34a605", + "outcome": "passed", + "packRuntime": { + "schemaVersion": 1, + "metric": "pack-check-wall-clock-sum-v1", + "packs": [ + { + "id": "ecommerce.feature.accounts", + "checkCount": 4, + "setupRuntimeMs": 847, + "criterionRuntimeMs": 15071, + "measuredRuntimeMs": 15918, + "budget": { + "status": "bounded", + "maxRuntimeMs": 18000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.cart", + "checkCount": 1, + "setupRuntimeMs": 716, + "criterionRuntimeMs": 6228, + "measuredRuntimeMs": 6944, + "budget": { + "status": "bounded", + "maxRuntimeMs": 42000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.catalog-discovery", + "checkCount": 2, + "setupRuntimeMs": 0, + "criterionRuntimeMs": 1944, + "measuredRuntimeMs": 1944, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.catalog-items", + "checkCount": 1, + "setupRuntimeMs": 0, + "criterionRuntimeMs": 243, + "measuredRuntimeMs": 243, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.checkout", + "checkCount": 1, + "setupRuntimeMs": 716, + "criterionRuntimeMs": 7173, + "measuredRuntimeMs": 7889, + "budget": { + "status": "bounded", + "maxRuntimeMs": 42000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.purchasing", + "checkCount": 1, + "setupRuntimeMs": 348, + "criterionRuntimeMs": 1160, + "measuredRuntimeMs": 1508, + "budget": { + "status": "bounded", + "maxRuntimeMs": 24000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.reviews", + "checkCount": 1, + "setupRuntimeMs": 1675, + "criterionRuntimeMs": 317, + "measuredRuntimeMs": 1992, + "budget": { + "status": "bounded", + "maxRuntimeMs": 22000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.warehouse-admin", + "checkCount": 2, + "setupRuntimeMs": 1090, + "criterionRuntimeMs": 4605, + "measuredRuntimeMs": 5695, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.inventory-dashboard", + "checkCount": 1, + "setupRuntimeMs": 5257, + "criterionRuntimeMs": 8, + "measuredRuntimeMs": 5265, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.order-cancellation-features", + "checkCount": 2, + "setupRuntimeMs": 759, + "criterionRuntimeMs": 11823, + "measuredRuntimeMs": 12582, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.recommendations", + "checkCount": 1, + "setupRuntimeMs": 283, + "criterionRuntimeMs": 5170, + "measuredRuntimeMs": 5453, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.sales-dashboard", + "checkCount": 2, + "setupRuntimeMs": 1945, + "criterionRuntimeMs": 5603, + "measuredRuntimeMs": 7548, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.stock-transfers-features", + "checkCount": 1, + "setupRuntimeMs": 378, + "criterionRuntimeMs": 1779, + "measuredRuntimeMs": 2157, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.deferred-access-specifications", + "checkCount": 1, + "setupRuntimeMs": 20798, + "criterionRuntimeMs": 4266, + "measuredRuntimeMs": 25064, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.deferred-durability-specifications", + "checkCount": 1, + "setupRuntimeMs": 125390, + "criterionRuntimeMs": 42254, + "measuredRuntimeMs": 167644, + "budget": { + "status": "bounded", + "maxRuntimeMs": 720000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.deferred-integrity-specifications", + "checkCount": 1, + "setupRuntimeMs": 40494, + "criterionRuntimeMs": 37105, + "measuredRuntimeMs": 77599, + "budget": { + "status": "bounded", + "maxRuntimeMs": 400000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.scheduled-restocks-features", + "checkCount": 3, + "setupRuntimeMs": 61406, + "criterionRuntimeMs": 70338, + "measuredRuntimeMs": 131744, + "budget": { + "status": "bounded", + "maxRuntimeMs": 150000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.server-time-specifications", + "checkCount": 1, + "setupRuntimeMs": 26228, + "criterionRuntimeMs": 114781, + "measuredRuntimeMs": 141009, + "budget": { + "status": "bounded", + "maxRuntimeMs": 300000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.cancellation-accounting-specifications", + "checkCount": 1, + "setupRuntimeMs": 578, + "criterionRuntimeMs": 11463, + "measuredRuntimeMs": 12041, + "budget": { + "status": "bounded", + "maxRuntimeMs": 24000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.catalog-management", + "checkCount": 2, + "setupRuntimeMs": 3732, + "criterionRuntimeMs": 25, + "measuredRuntimeMs": 3757, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.customer-profile", + "checkCount": 1, + "setupRuntimeMs": 494, + "criterionRuntimeMs": 5071, + "measuredRuntimeMs": 5565, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.faceted-search", + "checkCount": 2, + "setupRuntimeMs": 44444, + "criterionRuntimeMs": 25590, + "measuredRuntimeMs": 70034, + "budget": { + "status": "bounded", + "maxRuntimeMs": 141000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.fulfilment-queue", + "checkCount": 2, + "setupRuntimeMs": 1045, + "criterionRuntimeMs": 28695, + "measuredRuntimeMs": 29740, + "budget": { + "status": "bounded", + "maxRuntimeMs": 76000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.inventory-conservation-specifications", + "checkCount": 5, + "setupRuntimeMs": 2341, + "criterionRuntimeMs": 56574, + "measuredRuntimeMs": 58915, + "budget": { + "status": "bounded", + "maxRuntimeMs": 138000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.managed-support", + "checkCount": 1, + "setupRuntimeMs": 761, + "criterionRuntimeMs": 6654, + "measuredRuntimeMs": 7415, + "budget": { + "status": "bounded", + "maxRuntimeMs": 55000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.notification-preferences", + "checkCount": 1, + "setupRuntimeMs": 559, + "criterionRuntimeMs": 5076, + "measuredRuntimeMs": 5635, + "budget": { + "status": "bounded", + "maxRuntimeMs": 40000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.operations-access-specifications", + "checkCount": 3, + "setupRuntimeMs": 9646, + "criterionRuntimeMs": 38582, + "measuredRuntimeMs": 48228, + "budget": { + "status": "bounded", + "maxRuntimeMs": 98000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.promotion-rules", + "checkCount": 1, + "setupRuntimeMs": 498, + "criterionRuntimeMs": 371, + "measuredRuntimeMs": 869, + "budget": { + "status": "bounded", + "maxRuntimeMs": 45000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.review-access-specifications", + "checkCount": 1, + "setupRuntimeMs": 4095, + "criterionRuntimeMs": 7448, + "measuredRuntimeMs": 11543, + "budget": { + "status": "bounded", + "maxRuntimeMs": 62000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.staff-access", + "checkCount": 1, + "setupRuntimeMs": 0, + "criterionRuntimeMs": 712, + "measuredRuntimeMs": 712, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.staff-roles", + "checkCount": 1, + "setupRuntimeMs": 474, + "criterionRuntimeMs": 27, + "measuredRuntimeMs": 501, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.stock-alerts", + "checkCount": 1, + "setupRuntimeMs": 5795, + "criterionRuntimeMs": 12501, + "measuredRuntimeMs": 18296, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.support-history", + "checkCount": 1, + "setupRuntimeMs": 855, + "criterionRuntimeMs": 1539, + "measuredRuntimeMs": 2394, + "budget": { + "status": "bounded", + "maxRuntimeMs": 50000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.support-intake", + "checkCount": 1, + "setupRuntimeMs": 0, + "criterionRuntimeMs": 530, + "measuredRuntimeMs": 530, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.support-triage", + "checkCount": 3, + "setupRuntimeMs": 757, + "criterionRuntimeMs": 10890, + "measuredRuntimeMs": 11647, + "budget": { + "status": "bounded", + "maxRuntimeMs": 45000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.access-control", + "checkCount": 21, + "setupRuntimeMs": 29566, + "criterionRuntimeMs": 225679, + "measuredRuntimeMs": 255245, + "budget": { + "status": "bounded", + "maxRuntimeMs": 464000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.concurrency-safety", + "checkCount": 6, + "setupRuntimeMs": 26597, + "criterionRuntimeMs": 50285, + "measuredRuntimeMs": 76882, + "budget": { + "status": "bounded", + "maxRuntimeMs": 125000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.external-data-sync", + "checkCount": 3, + "setupRuntimeMs": 660, + "criterionRuntimeMs": 32618, + "measuredRuntimeMs": 33278, + "budget": { + "status": "bounded", + "maxRuntimeMs": 105000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.live-state", + "checkCount": 11, + "setupRuntimeMs": 20675, + "criterionRuntimeMs": 7583, + "measuredRuntimeMs": 28258, + "budget": { + "status": "bounded", + "maxRuntimeMs": 184000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.search-ordering", + "checkCount": 1, + "setupRuntimeMs": 21585, + "criterionRuntimeMs": 5314, + "measuredRuntimeMs": 26899, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.state-durability", + "checkCount": 8, + "setupRuntimeMs": 4047, + "criterionRuntimeMs": 58593, + "measuredRuntimeMs": 62640, + "budget": { + "status": "bounded", + "maxRuntimeMs": 408000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.transactional-integrity", + "checkCount": 6, + "setupRuntimeMs": 26816, + "criterionRuntimeMs": 36205, + "measuredRuntimeMs": 63021, + "budget": { + "status": "bounded", + "maxRuntimeMs": 100000 + }, + "exceeded": false + } + ] + }, + "mutations": { + "caught": 113, + "total": 113 + }, + "baselineDurationMs": 2300030, + "baselineOutput": "ecommerce-l3-11d743dd95a4-spacetime-mutation.runs/r1", + "baselineHarnessSha256Before": "7aa0044000ff319fd5c8b95575d9636a8835ded1afea277d16c7871dd30eadf8", + "baselineHarnessSha256After": "7aa0044000ff319fd5c8b95575d9636a8835ded1afea277d16c7871dd30eadf8", + "workers": [ + { + "index": 0, + "runIndex": 0, + "artifact": "ecommerce-l3-11d743dd95a4-spacetime-mutation.runs/r1-workers/w1.json", + "mutationIds": [ + "staff-admin-access-survives-role-removal", + "catalog-seeds-the-wrong-air-purifier-price", + "cart-is-deleted-when-owner-disconnects", + "guest-purchase-falls-back-to-the-admin-account", + "purchases-do-not-leave-the-warehouses", + "stock-view-ignores-update-across-app-server-stop", + "cancelled-order-remains-in-revenue-invariant", + "recommendations-ignore-pending-purchases", + "completed-restock-remains-pending", + "customer-profile-view-leaks-another-account", + "notification-preferences-leak-across-accounts", + "stock-alert-is-sent-after-every-restock", + "nonpositive-cart-quantity-is-treated-as-removal", + "stored-support-replies-are-hidden-after-reload", + "support-history-leaks-to-signed-out-visitors" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-11d743dd95a4-spacetime-mutation.runs/r1-workers/w1.stdout.log", + "stderr": "ecommerce-l3-11d743dd95a4-spacetime-mutation.runs/r1-workers/w1.stderr.log" + } + }, + { + "index": 1, + "runIndex": 1, + "artifact": "ecommerce-l3-11d743dd95a4-spacetime-mutation.runs/r1-workers/w2.json", + "mutationIds": [ + "shipping-counts-sale-twice", + "catalog-tie-breaks-in-reverse-alphabetical-order--01-catalog-ranking", + "signin-binds-the-second-client-to-a-different-account", + "direct-purchases-are-attributed-to-the-system-account", + "review-purchase-eligibility-is-not-checked", + "stock-view-keeps-pre-reconnect-snapshot", + "operator-authorization-allows-customer-transfer", + "purchases-do-not-affect-best-sellers", + "pending-restock-timer-is-static", + "faceted-search-ignores-category", + "customers-can-create-promotions", + "stock-alerts-are-visible-to-other-customers", + "admin-restock-preserves-existing-stock", + "saving-notification-preferences-resets-the-toggles" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-11d743dd95a4-spacetime-mutation.runs/r1-workers/w2.stdout.log", + "stderr": "ecommerce-l3-11d743dd95a4-spacetime-mutation.runs/r1-workers/w2.stderr.log" + } + }, + { + "index": 2, + "runIndex": 2, + "artifact": "ecommerce-l3-11d743dd95a4-spacetime-mutation.runs/r1-workers/w3.json", + "mutationIds": [ + "restock-client-snapshot-overwrites-concurrent-purchases", + "catalog-tie-breaks-in-reverse-alphabetical-order--01-core", + "checkout-does-not-empty-the-basic-cart", + "direct-restock-does-not-require-an-admin", + "eligible-review-is-accepted-without-being-stored", + "open-review-list-snapshots-on-selection", + "customer-can-ship-order-direct-1-1", + "queue-warehouse-reports-west", + "due-restock-omits-ledger-entry", + "active-search-uses-purchase-ranking", + "promotion-rule-stores-the-wrong-discount", + "support-history-is-lost-on-fresh-account-login", + "direct-review-access-is-not-checked", + "saving-a-staff-role-snaps-the-input-back-to-the-stored-role" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-11d743dd95a4-spacetime-mutation.runs/r1-workers/w3.stdout.log", + "stderr": "ecommerce-l3-11d743dd95a4-spacetime-mutation.runs/r1-workers/w3.stderr.log" + } + }, + { + "index": 3, + "runIndex": 3, + "artifact": "ecommerce-l3-11d743dd95a4-spacetime-mutation.runs/r1-workers/w4.json", + "mutationIds": [ + "signup-binds-the-new-account-to-the-admin-session", + "purchase-does-not-update-ranking-count", + "new-review-is-accepted-without-being-stored", + "direct-purchase-ignores-the-stored-price", + "cart-line-lookup-ignores-cart-ownership", + "open-review-list-renders-each-review-twice", + "customer-can-cancel-foreign-order-1-1", + "transfer-creates-stock-during-race", + "cancelled-restock-remains-pending", + "faceted-search-next-page-does-not-advance", + "staff-cannot-open-staff-tools", + "support-history-leaks-across-customers", + "support-history-rows-are-hidden", + "fulfilment-queue-is-frozen-at-page-load" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-11d743dd95a4-spacetime-mutation.runs/r1-workers/w4.stdout.log", + "stderr": "ecommerce-l3-11d743dd95a4-spacetime-mutation.runs/r1-workers/w4.stderr.log" + } + }, + { + "index": 4, + "runIndex": 4, + "artifact": "ecommerce-l3-11d743dd95a4-spacetime-mutation.runs/r1-workers/w5.json", + "mutationIds": [ + "duplicate-signup-is-silently-ignored", + "signed-out-purchase-bypasses-account-check", + "repeat-review-inserts-a-second-row", + "account-state-token-is-not-restored-after-reload", + "purchase-does-not-reserve-stock-last-unit", + "cancel-does-not-restore-stock-feature", + "ship-acknowledges-without-changing-status", + "catalog-search-ignores-the-query", + "restart-restock-runs-early", + "managed-support-leaks-and-accepts-cross-account-replies", + "customers-can-open-staff-tools", + "visitor-support-reference-is-hidden", + "authorized-restock-does-not-change-stock", + "low-stock-list-is-frozen-at-page-load" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-11d743dd95a4-spacetime-mutation.runs/r1-workers/w5.stdout.log", + "stderr": "ecommerce-l3-11d743dd95a4-spacetime-mutation.runs/r1-workers/w5.stderr.log" + } + }, + { + "index": 5, + "runIndex": 5, + "artifact": "ecommerce-l3-11d743dd95a4-spacetime-mutation.runs/r1-workers/w6.json", + "mutationIds": [ + "signin-does-not-verify-the-password", + "buy-now-creates-orders-without-reserving-stock--01-buying", + "review-average-counts-rows-instead-of-ratings", + "reconnect-discards-the-visible-account-state", + "existing-cart-line-does-not-increment", + "cancel-does-not-restore-stock-fresh-client", + "progression-customer-sees-fulfilment-content", + "admin-total-stock-is-not-rendered", + "catalog-product-is-not-published", + "managed-support-replies-are-empty", + "administrator-role-assignment-is-discarded", + "support-assignment-is-discarded", + "low-stock-threshold-is-two-units", + "category-totals-are-frozen-at-page-load" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-11d743dd95a4-spacetime-mutation.runs/r1-workers/w6.stdout.log", + "stderr": "ecommerce-l3-11d743dd95a4-spacetime-mutation.runs/r1-workers/w6.stderr.log" + } + }, + { + "index": 6, + "runIndex": 6, + "artifact": "ecommerce-l3-11d743dd95a4-spacetime-mutation.runs/r1-workers/w7.json", + "mutationIds": [ + "signout-keeps-the-account-session", + "buy-now-records-the-wrong-order-total", + "every-signed-in-customer-is-treated-as-an-admin", + "order-views-return-every-customers-orders", + "checkout-does-not-empty-cart", + "cancel-restores-stock-but-keeps-pending-status", + "operator-authorization-allows-customer-shipping", + "customers-can-schedule-restocks", + "catalog-variants-are-discarded", + "managed-support-live-replies-stay-at-initial-snapshot", + "staff-can-assign-roles", + "support-priority-is-discarded", + "category-totals-count-only-since-the-dashboard-opened", + "warehouse-totals-are-frozen-at-page-load" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-11d743dd95a4-spacetime-mutation.runs/r1-workers/w7.stdout.log", + "stderr": "ecommerce-l3-11d743dd95a4-spacetime-mutation.runs/r1-workers/w7.stderr.log" + } + }, + { + "index": 7, + "runIndex": 7, + "artifact": "ecommerce-l3-11d743dd95a4-spacetime-mutation.runs/r1-workers/w8.json", + "mutationIds": [ + "session-token-is-not-persisted-for-reload", + "existing-cart-line-does-not-increment-basic-cart", + "warehouse-view-omits-west", + "admin-revenue-double-counts-every-order", + "stock-subscription-snapshotted-once", + "cancelled-order-remains-in-revenue-feature", + "transfer-debits-source-without-crediting-existing-destination", + "scheduled-restock-execution-queue-is-process-local", + "profile-is-lost-on-fresh-account-login", + "notification-preferences-are-not-saved", + "stock-alert-delivery-is-suppressed", + "support-status-is-discarded", + "profile-summary-ignores-a-profile-saved-this-session", + "transfer-skips-the-source-holding-check" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-11d743dd95a4-spacetime-mutation.runs/r1-workers/w8.stdout.log", + "stderr": "ecommerce-l3-11d743dd95a4-spacetime-mutation.runs/r1-workers/w8.stderr.log" + } + } + ] + } + ], + "stable": true, + "sameImage": true, + "sameHarness": true, + "harnessSha256": "7aa0044000ff319fd5c8b95575d9636a8835ded1afea277d16c7871dd30eadf8", + "qualifiedCheckKeys": [ + "ecommerce.feature.accounts.accounts.1a", + "ecommerce.feature.accounts.accounts.1b", + "ecommerce.feature.accounts.accounts.1c", + "ecommerce.feature.accounts.accounts.1d", + "ecommerce.feature.cart-checkout.cart.4a", + "ecommerce.feature.cart-checkout.cart.4d", + "ecommerce.feature.catalog.catalog-ranking.2b", + "ecommerce.feature.catalog.catalog-search.2d", + "ecommerce.feature.catalog.catalog-values.2a", + "ecommerce.feature.purchasing.purchase-order.3c", + "ecommerce.feature.reviews.reviews.6a", + "ecommerce.feature.warehouse-admin.admin-write.103a", + "ecommerce.feature.warehouse-admin.warehouse-view.7b", + "ecommerce.inventory-operations.operational-views.5c", + "ecommerce.inventory-operations.operational-views.5d", + "ecommerce.inventory-operations.operational-views.5e", + "ecommerce.inventory-operations.operational-views.5f", + "ecommerce.inventory-operations.shipping-accounting.202e", + "ecommerce.inventory-operations.stock-conservation.202a", + "ecommerce.inventory-operations.stock-conservation.202b", + "ecommerce.inventory-operations.stock-conservation.202c", + "ecommerce.inventory-operations.stock-conservation.202d", + "ecommerce.inventory-operations.warehouse-transfer.2a", + "ecommerce.l3.deferred-access.scheduled-work-access.317a", + "ecommerce.l3.deferred-durability.restart-survival.311a", + "ecommerce.l3.deferred-integrity.exactly-once.311a", + "ecommerce.l3.scheduled-restocks.scheduled-restocks.302a", + "ecommerce.l3.scheduled-restocks.scheduled-restocks.305a", + "ecommerce.l3.scheduled-restocks.scheduled-restocks.306a", + "ecommerce.l3.server-time.server-time.312a", + "ecommerce.operations-access.fulfilment-queue.1b", + "ecommerce.operations-access.fulfilment-queue.1c", + "ecommerce.operations-access.operator-authorization.201a", + "ecommerce.operations-access.operator-authorization.201c", + "ecommerce.operations-access.order-owner.204a", + "ecommerce.progression.catalog-management.catalog-management.622a", + "ecommerce.progression.catalog-management.catalog-management.622b", + "ecommerce.progression.customer-profile.customer-profile.620c", + "ecommerce.progression.faceted-search.faceted-search.401a", + "ecommerce.progression.faceted-search.faceted-search.402a", + "ecommerce.progression.managed-support.managed-support.613c", + "ecommerce.progression.notification-preferences.notification-preferences.630c", + "ecommerce.progression.promotion-rules.promotion-rule-values.620a", + "ecommerce.progression.review-access-specifications.review-eligibility-direct.618a", + "ecommerce.progression.staff-access.staff-access.601a", + "ecommerce.progression.staff-roles.staff-roles.621c", + "ecommerce.progression.stock-alerts.stock-alert-delivery.631c", + "ecommerce.progression.support-history.support-history.612c", + "ecommerce.progression.support-intake.support-intake.610a", + "ecommerce.progression.support-triage.support-assignment.611a", + "ecommerce.progression.support-triage.support-priority.611b", + "ecommerce.progression.support-triage.support-status.611c", + "ecommerce.returns-pricing.cancellation-and-return.3a", + "ecommerce.returns-pricing.cancellation-and-return.3b", + "ecommerce.returns-pricing.refund-accounting.203a", + "ecommerce.spec.access-control.cart-boundary.109a", + "ecommerce.spec.access-control.cart-boundary.109b", + "ecommerce.spec.access-control.customer-profile-privacy.620b", + "ecommerce.spec.access-control.fulfilment-area-boundary.1d", + "ecommerce.spec.access-control.managed-support-privacy.613b", + "ecommerce.spec.access-control.notification-preferences-privacy.630b", + "ecommerce.spec.access-control.order-ownership.106a", + "ecommerce.spec.access-control.promotion-management-boundary.620b", + "ecommerce.spec.access-control.purchase-attribution.102a", + "ecommerce.spec.access-control.purchase-session.101a", + "ecommerce.spec.access-control.review-eligibility.108a", + "ecommerce.spec.access-control.review-eligibility.108b", + "ecommerce.spec.access-control.signed-out-purchase.3a", + "ecommerce.spec.access-control.staff-area-boundary.601b", + "ecommerce.spec.access-control.staff-role-boundary.621b", + "ecommerce.spec.access-control.staff-role-revocation.621d", + "ecommerce.spec.access-control.stock-alert-privacy.631b", + "ecommerce.spec.access-control.support-history-logout.612d", + "ecommerce.spec.access-control.support-history-privacy.612b", + "ecommerce.spec.access-control.warehouse-area-boundary.7a", + "ecommerce.spec.access-control.warehouse-write-boundary.103b", + "ecommerce.spec.concurrency-safety.duplicate-checkout.203a", + "ecommerce.spec.concurrency-safety.duplicate-checkout.203b", + "ecommerce.spec.concurrency-safety.last-unit.201a", + "ecommerce.spec.concurrency-safety.last-unit.201b", + "ecommerce.spec.concurrency-safety.last-unit.201c", + "ecommerce.spec.concurrency-safety.restock-race.202a", + "ecommerce.spec.external-data-sync.external-stock.901a", + "ecommerce.spec.external-data-sync.external-stock.901c", + "ecommerce.spec.external-data-sync.external-stock.901d", + "ecommerce.spec.live-state.fulfilment-queue.1a", + "ecommerce.spec.live-state.inventory-dashboard.5a", + "ecommerce.spec.live-state.managed-support.613a", + "ecommerce.spec.live-state.open-list.902a", + "ecommerce.spec.live-state.purchase-stock.3b", + "ecommerce.spec.live-state.ranking.2c", + "ecommerce.spec.live-state.rating.6c", + "ecommerce.spec.live-state.sales-dashboard.5b", + "ecommerce.spec.live-state.shared-cart.4c", + "ecommerce.spec.live-state.stock-transfers.2b", + "ecommerce.spec.live-state.warehouse-stock.7c", + "ecommerce.spec.search-ordering.search-ordering.402b", + "ecommerce.spec.state-durability.account-state-recovery.105a", + "ecommerce.spec.state-durability.account-state-recovery.105b", + "ecommerce.spec.state-durability.cart-reload.4b", + "ecommerce.spec.state-durability.customer-profile-reload.620a", + "ecommerce.spec.state-durability.notification-preferences-reload.630a", + "ecommerce.spec.state-durability.session-reload.1e", + "ecommerce.spec.state-durability.staff-role-reload.621a", + "ecommerce.spec.state-durability.support-history-reload.612a", + "ecommerce.spec.transactional-integrity.books-balance.107a", + "ecommerce.spec.transactional-integrity.books-balance.107b", + "ecommerce.spec.transactional-integrity.server-price.104a", + "ecommerce.spec.transactional-integrity.stock-alert-deduplication.631a", + "ecommerce.spec.transactional-integrity.stock-transfer-overdraw.2c", + "ecommerce.spec.transactional-integrity.unique-review.6b" + ], + "featureCatalog": { + "contentSha256": "863e2a2b09f7b00d1b9755607347364e3ad9013d0ceea58ceca93b1f933f3e45", + "id": "ecommerce.questlines" + }, + "diagnostic": false, + "ok": true + } +} diff --git a/tools/stack-bench/qualification-evidence/ecommerce-l3-43d01f644/spacetime-reference.json b/tools/stack-bench/qualification-evidence/ecommerce-l3-43d01f644/spacetime-reference.json new file mode 100644 index 00000000000..77af67d6945 --- /dev/null +++ b/tools/stack-bench/qualification-evidence/ecommerce-l3-43d01f644/spacetime-reference.json @@ -0,0 +1,733 @@ +{ + "artifactSchemaVersion": 2, + "kind": "reference_qualification", + "id": "reference-live-spacetime-20260916171515-31-reference", + "attempt": { + "id": "reference-live-spacetime-20260916171515-31-reference", + "parentId": null + }, + "timestamps": { + "startedAt": "2026-09-16T17:15:15.850Z", + "completedAt": "2026-09-16T18:07:26.984Z" + }, + "identities": { + "engine": { + "id": "stack-bench", + "sha256": "31ffc8e48b22c397d10aa5ca2b6bc0680e9ae20fd8903bccc4d7db406a1478de" + }, + "recipe": { + "id": "ecommerce.progression-catalog", + "sha256": "11d743dd95a4671bdbb71c10f75b8405671f20a32c5312c9832c8ff9481e7ed5" + }, + "fixture": { + "id": "ecommerce-reference-spacetime", + "sha256": "825d5666db0f2082a217d3b5d9aba0178054a014224c9d2ab8ae91cf8112af3f" + }, + "calibration": { + "id": "ecommerce.dependency-l3-calibration", + "sha256": "578942627b3d6827609fb623361e1a672b4a602b65e0f1c501048b346438e954" + }, + "experiment": null, + "agentAdapter": null, + "stackAdapter": { + "id": "spacetime", + "sha256": null + }, + "packs": [] + }, + "payload": { + "fixture": "ecommerce-reference-spacetime", + "fixtureSha256": "825d5666db0f2082a217d3b5d9aba0178054a014224c9d2ab8ae91cf8112af3f", + "requiredRepetitions": 1, + "isolation": "docker", + "runner": { + "schemaVersion": 1, + "mode": "appliance", + "platform": "linux", + "architecture": "x64", + "hostname": "docker-desktop", + "dockerEngineVersion": "29.6.2", + "dockerOs": "linux", + "dockerArchitecture": "x86_64", + "kernelVersion": "6.6.87.2-microsoft-standard-WSL2", + "cpuCount": 32, + "memoryBytes": 49232846848, + "containersRunning": 12, + "packageRegistry": "http://127.0.0.1:4873/" + }, + "qualificationScope": { + "checksSha256": "adc107253c217dc57e6b0648b083b5762f1358871f2764baad8cacfd3083eb10", + "executableSha256": "2d142aa52b18470145d996dba803dd5a5d14065fcf4f78ae8f0cfc38cb884cd5", + "kind": "reference", + "mutationSha256": null, + "recipe": { + "contentSha256": "11d743dd95a4671bdbb71c10f75b8405671f20a32c5312c9832c8ff9481e7ed5", + "id": "ecommerce.progression-catalog" + }, + "schemaVersion": 3, + "stack": { + "id": "spacetime", + "reference": { + "id": "ecommerce-reference-spacetime", + "sourceSha256": "825d5666db0f2082a217d3b5d9aba0178054a014224c9d2ab8ae91cf8112af3f" + }, + "version": "1.4.0" + }, + "sha256": "b9fb43b970b4a2f1ccbeb8f5b7c428cc6205a66095846465532987221a0bd54a" + }, + "mutationControl": false, + "runs": [ + { + "repetition": 1, + "output": "ecommerce-l3-11d743dd95a4-spacetime-mutation.runs/r1", + "durationMs": 2300030, + "processError": null, + "harnessSha256Before": "7aa0044000ff319fd5c8b95575d9636a8835ded1afea277d16c7871dd30eadf8", + "harnessSha256After": "7aa0044000ff319fd5c8b95575d9636a8835ded1afea277d16c7871dd30eadf8", + "ok": true, + "failures": [], + "runId": "ecommerce-spacetime-run0-20260916171516-29d83d49", + "score": "180/180", + "imageId": "sha256:32ff9a9e519ba9d1af2fe72f24622caa8ca7a9f2baf2338c6b1e0435e6ac5455", + "criteria": 111, + "zeroPointCriteria": 0, + "fingerprint": "01676f87359c0bfc4b294128f48746ef655e9e4b61734439a2ea4b95dc34a605", + "outcome": "passed", + "packRuntime": { + "schemaVersion": 1, + "metric": "pack-check-wall-clock-sum-v1", + "packs": [ + { + "id": "ecommerce.feature.accounts", + "checkCount": 4, + "setupRuntimeMs": 847, + "criterionRuntimeMs": 15071, + "measuredRuntimeMs": 15918, + "budget": { + "status": "bounded", + "maxRuntimeMs": 18000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.cart", + "checkCount": 1, + "setupRuntimeMs": 716, + "criterionRuntimeMs": 6228, + "measuredRuntimeMs": 6944, + "budget": { + "status": "bounded", + "maxRuntimeMs": 42000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.catalog-discovery", + "checkCount": 2, + "setupRuntimeMs": 0, + "criterionRuntimeMs": 1944, + "measuredRuntimeMs": 1944, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.catalog-items", + "checkCount": 1, + "setupRuntimeMs": 0, + "criterionRuntimeMs": 243, + "measuredRuntimeMs": 243, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.checkout", + "checkCount": 1, + "setupRuntimeMs": 716, + "criterionRuntimeMs": 7173, + "measuredRuntimeMs": 7889, + "budget": { + "status": "bounded", + "maxRuntimeMs": 42000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.purchasing", + "checkCount": 1, + "setupRuntimeMs": 348, + "criterionRuntimeMs": 1160, + "measuredRuntimeMs": 1508, + "budget": { + "status": "bounded", + "maxRuntimeMs": 24000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.reviews", + "checkCount": 1, + "setupRuntimeMs": 1675, + "criterionRuntimeMs": 317, + "measuredRuntimeMs": 1992, + "budget": { + "status": "bounded", + "maxRuntimeMs": 22000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.warehouse-admin", + "checkCount": 2, + "setupRuntimeMs": 1090, + "criterionRuntimeMs": 4605, + "measuredRuntimeMs": 5695, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.inventory-dashboard", + "checkCount": 1, + "setupRuntimeMs": 5257, + "criterionRuntimeMs": 8, + "measuredRuntimeMs": 5265, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.order-cancellation-features", + "checkCount": 2, + "setupRuntimeMs": 759, + "criterionRuntimeMs": 11823, + "measuredRuntimeMs": 12582, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.recommendations", + "checkCount": 1, + "setupRuntimeMs": 283, + "criterionRuntimeMs": 5170, + "measuredRuntimeMs": 5453, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.sales-dashboard", + "checkCount": 2, + "setupRuntimeMs": 1945, + "criterionRuntimeMs": 5603, + "measuredRuntimeMs": 7548, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.stock-transfers-features", + "checkCount": 1, + "setupRuntimeMs": 378, + "criterionRuntimeMs": 1779, + "measuredRuntimeMs": 2157, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.deferred-access-specifications", + "checkCount": 1, + "setupRuntimeMs": 20798, + "criterionRuntimeMs": 4266, + "measuredRuntimeMs": 25064, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.deferred-durability-specifications", + "checkCount": 1, + "setupRuntimeMs": 125390, + "criterionRuntimeMs": 42254, + "measuredRuntimeMs": 167644, + "budget": { + "status": "bounded", + "maxRuntimeMs": 720000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.deferred-integrity-specifications", + "checkCount": 1, + "setupRuntimeMs": 40494, + "criterionRuntimeMs": 37105, + "measuredRuntimeMs": 77599, + "budget": { + "status": "bounded", + "maxRuntimeMs": 400000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.scheduled-restocks-features", + "checkCount": 3, + "setupRuntimeMs": 61406, + "criterionRuntimeMs": 70338, + "measuredRuntimeMs": 131744, + "budget": { + "status": "bounded", + "maxRuntimeMs": 150000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.server-time-specifications", + "checkCount": 1, + "setupRuntimeMs": 26228, + "criterionRuntimeMs": 114781, + "measuredRuntimeMs": 141009, + "budget": { + "status": "bounded", + "maxRuntimeMs": 300000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.cancellation-accounting-specifications", + "checkCount": 1, + "setupRuntimeMs": 578, + "criterionRuntimeMs": 11463, + "measuredRuntimeMs": 12041, + "budget": { + "status": "bounded", + "maxRuntimeMs": 24000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.catalog-management", + "checkCount": 2, + "setupRuntimeMs": 3732, + "criterionRuntimeMs": 25, + "measuredRuntimeMs": 3757, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.customer-profile", + "checkCount": 1, + "setupRuntimeMs": 494, + "criterionRuntimeMs": 5071, + "measuredRuntimeMs": 5565, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.faceted-search", + "checkCount": 2, + "setupRuntimeMs": 44444, + "criterionRuntimeMs": 25590, + "measuredRuntimeMs": 70034, + "budget": { + "status": "bounded", + "maxRuntimeMs": 141000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.fulfilment-queue", + "checkCount": 2, + "setupRuntimeMs": 1045, + "criterionRuntimeMs": 28695, + "measuredRuntimeMs": 29740, + "budget": { + "status": "bounded", + "maxRuntimeMs": 76000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.inventory-conservation-specifications", + "checkCount": 5, + "setupRuntimeMs": 2341, + "criterionRuntimeMs": 56574, + "measuredRuntimeMs": 58915, + "budget": { + "status": "bounded", + "maxRuntimeMs": 138000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.managed-support", + "checkCount": 1, + "setupRuntimeMs": 761, + "criterionRuntimeMs": 6654, + "measuredRuntimeMs": 7415, + "budget": { + "status": "bounded", + "maxRuntimeMs": 55000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.notification-preferences", + "checkCount": 1, + "setupRuntimeMs": 559, + "criterionRuntimeMs": 5076, + "measuredRuntimeMs": 5635, + "budget": { + "status": "bounded", + "maxRuntimeMs": 40000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.operations-access-specifications", + "checkCount": 3, + "setupRuntimeMs": 9646, + "criterionRuntimeMs": 38582, + "measuredRuntimeMs": 48228, + "budget": { + "status": "bounded", + "maxRuntimeMs": 98000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.promotion-rules", + "checkCount": 1, + "setupRuntimeMs": 498, + "criterionRuntimeMs": 371, + "measuredRuntimeMs": 869, + "budget": { + "status": "bounded", + "maxRuntimeMs": 45000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.review-access-specifications", + "checkCount": 1, + "setupRuntimeMs": 4095, + "criterionRuntimeMs": 7448, + "measuredRuntimeMs": 11543, + "budget": { + "status": "bounded", + "maxRuntimeMs": 62000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.staff-access", + "checkCount": 1, + "setupRuntimeMs": 0, + "criterionRuntimeMs": 712, + "measuredRuntimeMs": 712, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.staff-roles", + "checkCount": 1, + "setupRuntimeMs": 474, + "criterionRuntimeMs": 27, + "measuredRuntimeMs": 501, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.stock-alerts", + "checkCount": 1, + "setupRuntimeMs": 5795, + "criterionRuntimeMs": 12501, + "measuredRuntimeMs": 18296, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.support-history", + "checkCount": 1, + "setupRuntimeMs": 855, + "criterionRuntimeMs": 1539, + "measuredRuntimeMs": 2394, + "budget": { + "status": "bounded", + "maxRuntimeMs": 50000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.support-intake", + "checkCount": 1, + "setupRuntimeMs": 0, + "criterionRuntimeMs": 530, + "measuredRuntimeMs": 530, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.support-triage", + "checkCount": 3, + "setupRuntimeMs": 757, + "criterionRuntimeMs": 10890, + "measuredRuntimeMs": 11647, + "budget": { + "status": "bounded", + "maxRuntimeMs": 45000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.access-control", + "checkCount": 21, + "setupRuntimeMs": 29566, + "criterionRuntimeMs": 225679, + "measuredRuntimeMs": 255245, + "budget": { + "status": "bounded", + "maxRuntimeMs": 464000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.concurrency-safety", + "checkCount": 6, + "setupRuntimeMs": 26597, + "criterionRuntimeMs": 50285, + "measuredRuntimeMs": 76882, + "budget": { + "status": "bounded", + "maxRuntimeMs": 125000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.external-data-sync", + "checkCount": 3, + "setupRuntimeMs": 660, + "criterionRuntimeMs": 32618, + "measuredRuntimeMs": 33278, + "budget": { + "status": "bounded", + "maxRuntimeMs": 105000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.live-state", + "checkCount": 11, + "setupRuntimeMs": 20675, + "criterionRuntimeMs": 7583, + "measuredRuntimeMs": 28258, + "budget": { + "status": "bounded", + "maxRuntimeMs": 184000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.search-ordering", + "checkCount": 1, + "setupRuntimeMs": 21585, + "criterionRuntimeMs": 5314, + "measuredRuntimeMs": 26899, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.state-durability", + "checkCount": 8, + "setupRuntimeMs": 4047, + "criterionRuntimeMs": 58593, + "measuredRuntimeMs": 62640, + "budget": { + "status": "bounded", + "maxRuntimeMs": 408000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.transactional-integrity", + "checkCount": 6, + "setupRuntimeMs": 26816, + "criterionRuntimeMs": 36205, + "measuredRuntimeMs": 63021, + "budget": { + "status": "bounded", + "maxRuntimeMs": 100000 + }, + "exceeded": false + } + ] + }, + "mutations": null + } + ], + "stable": true, + "sameImage": true, + "sameHarness": true, + "harnessSha256": "7aa0044000ff319fd5c8b95575d9636a8835ded1afea277d16c7871dd30eadf8", + "qualifiedCheckKeys": [ + "ecommerce.feature.accounts.accounts.1a", + "ecommerce.feature.accounts.accounts.1b", + "ecommerce.feature.accounts.accounts.1c", + "ecommerce.feature.accounts.accounts.1d", + "ecommerce.feature.cart-checkout.cart.4a", + "ecommerce.feature.cart-checkout.cart.4d", + "ecommerce.feature.catalog.catalog-ranking.2b", + "ecommerce.feature.catalog.catalog-search.2d", + "ecommerce.feature.catalog.catalog-values.2a", + "ecommerce.feature.purchasing.purchase-order.3c", + "ecommerce.feature.reviews.reviews.6a", + "ecommerce.feature.warehouse-admin.admin-write.103a", + "ecommerce.feature.warehouse-admin.warehouse-view.7b", + "ecommerce.inventory-operations.operational-views.5c", + "ecommerce.inventory-operations.operational-views.5d", + "ecommerce.inventory-operations.operational-views.5e", + "ecommerce.inventory-operations.operational-views.5f", + "ecommerce.inventory-operations.shipping-accounting.202e", + "ecommerce.inventory-operations.stock-conservation.202a", + "ecommerce.inventory-operations.stock-conservation.202b", + "ecommerce.inventory-operations.stock-conservation.202c", + "ecommerce.inventory-operations.stock-conservation.202d", + "ecommerce.inventory-operations.warehouse-transfer.2a", + "ecommerce.l3.deferred-access.scheduled-work-access.317a", + "ecommerce.l3.deferred-durability.restart-survival.311a", + "ecommerce.l3.deferred-integrity.exactly-once.311a", + "ecommerce.l3.scheduled-restocks.scheduled-restocks.302a", + "ecommerce.l3.scheduled-restocks.scheduled-restocks.305a", + "ecommerce.l3.scheduled-restocks.scheduled-restocks.306a", + "ecommerce.l3.server-time.server-time.312a", + "ecommerce.operations-access.fulfilment-queue.1b", + "ecommerce.operations-access.fulfilment-queue.1c", + "ecommerce.operations-access.operator-authorization.201a", + "ecommerce.operations-access.operator-authorization.201c", + "ecommerce.operations-access.order-owner.204a", + "ecommerce.progression.catalog-management.catalog-management.622a", + "ecommerce.progression.catalog-management.catalog-management.622b", + "ecommerce.progression.customer-profile.customer-profile.620c", + "ecommerce.progression.faceted-search.faceted-search.401a", + "ecommerce.progression.faceted-search.faceted-search.402a", + "ecommerce.progression.managed-support.managed-support.613c", + "ecommerce.progression.notification-preferences.notification-preferences.630c", + "ecommerce.progression.promotion-rules.promotion-rule-values.620a", + "ecommerce.progression.review-access-specifications.review-eligibility-direct.618a", + "ecommerce.progression.staff-access.staff-access.601a", + "ecommerce.progression.staff-roles.staff-roles.621c", + "ecommerce.progression.stock-alerts.stock-alert-delivery.631c", + "ecommerce.progression.support-history.support-history.612c", + "ecommerce.progression.support-intake.support-intake.610a", + "ecommerce.progression.support-triage.support-assignment.611a", + "ecommerce.progression.support-triage.support-priority.611b", + "ecommerce.progression.support-triage.support-status.611c", + "ecommerce.returns-pricing.cancellation-and-return.3a", + "ecommerce.returns-pricing.cancellation-and-return.3b", + "ecommerce.returns-pricing.refund-accounting.203a", + "ecommerce.spec.access-control.cart-boundary.109a", + "ecommerce.spec.access-control.cart-boundary.109b", + "ecommerce.spec.access-control.customer-profile-privacy.620b", + "ecommerce.spec.access-control.fulfilment-area-boundary.1d", + "ecommerce.spec.access-control.managed-support-privacy.613b", + "ecommerce.spec.access-control.notification-preferences-privacy.630b", + "ecommerce.spec.access-control.order-ownership.106a", + "ecommerce.spec.access-control.promotion-management-boundary.620b", + "ecommerce.spec.access-control.purchase-attribution.102a", + "ecommerce.spec.access-control.purchase-session.101a", + "ecommerce.spec.access-control.review-eligibility.108a", + "ecommerce.spec.access-control.review-eligibility.108b", + "ecommerce.spec.access-control.signed-out-purchase.3a", + "ecommerce.spec.access-control.staff-area-boundary.601b", + "ecommerce.spec.access-control.staff-role-boundary.621b", + "ecommerce.spec.access-control.staff-role-revocation.621d", + "ecommerce.spec.access-control.stock-alert-privacy.631b", + "ecommerce.spec.access-control.support-history-logout.612d", + "ecommerce.spec.access-control.support-history-privacy.612b", + "ecommerce.spec.access-control.warehouse-area-boundary.7a", + "ecommerce.spec.access-control.warehouse-write-boundary.103b", + "ecommerce.spec.concurrency-safety.duplicate-checkout.203a", + "ecommerce.spec.concurrency-safety.duplicate-checkout.203b", + "ecommerce.spec.concurrency-safety.last-unit.201a", + "ecommerce.spec.concurrency-safety.last-unit.201b", + "ecommerce.spec.concurrency-safety.last-unit.201c", + "ecommerce.spec.concurrency-safety.restock-race.202a", + "ecommerce.spec.external-data-sync.external-stock.901a", + "ecommerce.spec.external-data-sync.external-stock.901c", + "ecommerce.spec.external-data-sync.external-stock.901d", + "ecommerce.spec.live-state.fulfilment-queue.1a", + "ecommerce.spec.live-state.inventory-dashboard.5a", + "ecommerce.spec.live-state.managed-support.613a", + "ecommerce.spec.live-state.open-list.902a", + "ecommerce.spec.live-state.purchase-stock.3b", + "ecommerce.spec.live-state.ranking.2c", + "ecommerce.spec.live-state.rating.6c", + "ecommerce.spec.live-state.sales-dashboard.5b", + "ecommerce.spec.live-state.shared-cart.4c", + "ecommerce.spec.live-state.stock-transfers.2b", + "ecommerce.spec.live-state.warehouse-stock.7c", + "ecommerce.spec.search-ordering.search-ordering.402b", + "ecommerce.spec.state-durability.account-state-recovery.105a", + "ecommerce.spec.state-durability.account-state-recovery.105b", + "ecommerce.spec.state-durability.cart-reload.4b", + "ecommerce.spec.state-durability.customer-profile-reload.620a", + "ecommerce.spec.state-durability.notification-preferences-reload.630a", + "ecommerce.spec.state-durability.session-reload.1e", + "ecommerce.spec.state-durability.staff-role-reload.621a", + "ecommerce.spec.state-durability.support-history-reload.612a", + "ecommerce.spec.transactional-integrity.books-balance.107a", + "ecommerce.spec.transactional-integrity.books-balance.107b", + "ecommerce.spec.transactional-integrity.server-price.104a", + "ecommerce.spec.transactional-integrity.stock-alert-deduplication.631a", + "ecommerce.spec.transactional-integrity.stock-transfer-overdraw.2c", + "ecommerce.spec.transactional-integrity.unique-review.6b" + ], + "featureCatalog": { + "contentSha256": "863e2a2b09f7b00d1b9755607347364e3ad9013d0ceea58ceca93b1f933f3e45", + "id": "ecommerce.questlines" + }, + "diagnostic": false, + "ok": true + } +} diff --git a/tools/stack-bench/qualification-evidence/ecommerce-l3-78ccb6966/mongodb-mutation.json b/tools/stack-bench/qualification-evidence/ecommerce-l3-78ccb6966/mongodb-mutation.json new file mode 100644 index 00000000000..d7969706b60 --- /dev/null +++ b/tools/stack-bench/qualification-evidence/ecommerce-l3-78ccb6966/mongodb-mutation.json @@ -0,0 +1,952 @@ +{ + "artifactSchemaVersion": 2, + "kind": "reference_qualification", + "id": "reference-live-mongodb-20260917171216-30", + "attempt": { + "id": "reference-live-mongodb-20260917171216-30", + "parentId": null + }, + "timestamps": { + "startedAt": "2026-09-17T17:12:16.526Z", + "completedAt": "2026-09-17T18:05:00.352Z" + }, + "identities": { + "engine": { + "id": "stack-bench", + "sha256": "6562a1f38ed757804dc8a6f70ac3c36bb71e7cfd257fbfb4aacd1c30a7412bea" + }, + "recipe": { + "id": "ecommerce.progression-catalog", + "sha256": "add0647be965132c0b9702c5db3ba8265a01b0edc8ca5d820cc152e4ceeb5a89" + }, + "fixture": { + "id": "ecommerce-reference-mongodb", + "sha256": "0d21bbc4b2768f4077a81d676f0d4c87a65067dda8f2c5ffeb2fa9208381dc7e" + }, + "calibration": { + "id": "ecommerce.dependency-l3-calibration", + "sha256": "dc4bf3e29e5d5040becf8fdd846e7d3fd6419a27cb766c8c93a75f19f66c664b" + }, + "experiment": null, + "agentAdapter": null, + "stackAdapter": { + "id": "mongodb", + "sha256": null + }, + "packs": [] + }, + "payload": { + "fixture": "ecommerce-reference-mongodb", + "fixtureSha256": "0d21bbc4b2768f4077a81d676f0d4c87a65067dda8f2c5ffeb2fa9208381dc7e", + "requiredRepetitions": 1, + "isolation": "docker", + "runner": { + "schemaVersion": 1, + "mode": "appliance", + "platform": "linux", + "architecture": "x64", + "hostname": "docker-desktop", + "dockerEngineVersion": "29.6.2", + "dockerOs": "linux", + "dockerArchitecture": "x86_64", + "kernelVersion": "6.6.87.2-microsoft-standard-WSL2", + "cpuCount": 32, + "memoryBytes": 49232842752, + "containersRunning": 10, + "packageRegistry": "http://127.0.0.1:4873/" + }, + "qualificationScope": { + "checksSha256": "64d4f2af43f951e8c70d61ed1e64baf5f376ce3fa6031b1a9d79db2bd48aeaff", + "executableSha256": "dabe88d52dc6d3865f499888d3cbac167623282f053c9fc53523bea13b2aa977", + "kind": "mutation", + "mutationSha256": "30064c2cb9ef1e749a1080117920e423eb21c7fa8e296593a82778754da6c04c", + "recipe": { + "contentSha256": "add0647be965132c0b9702c5db3ba8265a01b0edc8ca5d820cc152e4ceeb5a89", + "id": "ecommerce.progression-catalog" + }, + "schemaVersion": 3, + "stack": { + "id": "mongodb", + "reference": { + "id": "ecommerce-reference-mongodb", + "sourceSha256": "0d21bbc4b2768f4077a81d676f0d4c87a65067dda8f2c5ffeb2fa9208381dc7e" + }, + "version": "1.5.0" + }, + "sha256": "d0f2cf64b83d3a7aed01102eda9a45877b67b20cbf2ca61aa601b82bc048a647" + }, + "mutationControl": true, + "runs": [ + { + "repetition": 1, + "output": "ecommerce-l3-add0647be965-mongodb-mutation.runs/r1-workers", + "durationMs": 3163756, + "processError": null, + "harnessSha256Before": "d423f94e24aae42fa30fcd169e387eeddf15f50c35cebdb4b461044b98e466f8", + "harnessSha256After": "d423f94e24aae42fa30fcd169e387eeddf15f50c35cebdb4b461044b98e466f8", + "ok": true, + "failures": [], + "runId": "reference-live-mongodb-20260917171216-30", + "score": "182/182", + "imageId": "sha256:32ff9a9e519ba9d1af2fe72f24622caa8ca7a9f2baf2338c6b1e0435e6ac5455", + "criteria": 113, + "zeroPointCriteria": 0, + "fingerprint": "0d6c57cc6ec1dd08dd5409aa619f28d1aa7c74e27644a80dd2312a0038b978cc", + "outcome": "passed", + "packRuntime": { + "schemaVersion": 1, + "metric": "pack-check-wall-clock-sum-v1", + "packs": [ + { + "id": "ecommerce.feature.accounts", + "checkCount": 4, + "setupRuntimeMs": 1220, + "criterionRuntimeMs": 15190, + "measuredRuntimeMs": 16410, + "budget": { + "status": "bounded", + "maxRuntimeMs": 18000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.cart", + "checkCount": 1, + "setupRuntimeMs": 649, + "criterionRuntimeMs": 6065, + "measuredRuntimeMs": 6714, + "budget": { + "status": "bounded", + "maxRuntimeMs": 42000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.catalog-discovery", + "checkCount": 2, + "setupRuntimeMs": 0, + "criterionRuntimeMs": 1853, + "measuredRuntimeMs": 1853, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.catalog-items", + "checkCount": 1, + "setupRuntimeMs": 0, + "criterionRuntimeMs": 287, + "measuredRuntimeMs": 287, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.checkout", + "checkCount": 1, + "setupRuntimeMs": 649, + "criterionRuntimeMs": 10772, + "measuredRuntimeMs": 11421, + "budget": { + "status": "bounded", + "maxRuntimeMs": 42000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.purchasing", + "checkCount": 1, + "setupRuntimeMs": 347, + "criterionRuntimeMs": 1160, + "measuredRuntimeMs": 1507, + "budget": { + "status": "bounded", + "maxRuntimeMs": 24000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.reviews", + "checkCount": 1, + "setupRuntimeMs": 21635, + "criterionRuntimeMs": 329, + "measuredRuntimeMs": 21964, + "budget": { + "status": "bounded", + "maxRuntimeMs": 22000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.warehouse-admin", + "checkCount": 2, + "setupRuntimeMs": 1645, + "criterionRuntimeMs": 4325, + "measuredRuntimeMs": 5970, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.inventory-dashboard", + "checkCount": 1, + "setupRuntimeMs": 4374, + "criterionRuntimeMs": 8, + "measuredRuntimeMs": 4382, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.order-cancellation-features", + "checkCount": 2, + "setupRuntimeMs": 1074, + "criterionRuntimeMs": 16359, + "measuredRuntimeMs": 17433, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.recommendations", + "checkCount": 1, + "setupRuntimeMs": 343, + "criterionRuntimeMs": 5170, + "measuredRuntimeMs": 5513, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.sales-dashboard", + "checkCount": 2, + "setupRuntimeMs": 2288, + "criterionRuntimeMs": 4999, + "measuredRuntimeMs": 7287, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.stock-transfers-features", + "checkCount": 1, + "setupRuntimeMs": 508, + "criterionRuntimeMs": 2627, + "measuredRuntimeMs": 3135, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.deferred-access-specifications", + "checkCount": 1, + "setupRuntimeMs": 20956, + "criterionRuntimeMs": 4235, + "measuredRuntimeMs": 25191, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.deferred-durability-specifications", + "checkCount": 1, + "setupRuntimeMs": 128627, + "criterionRuntimeMs": 39135, + "measuredRuntimeMs": 167762, + "budget": { + "status": "bounded", + "maxRuntimeMs": 720000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.deferred-integrity-specifications", + "checkCount": 1, + "setupRuntimeMs": 42964, + "criterionRuntimeMs": 39193, + "measuredRuntimeMs": 82157, + "budget": { + "status": "bounded", + "maxRuntimeMs": 400000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.scheduled-restocks-features", + "checkCount": 3, + "setupRuntimeMs": 61594, + "criterionRuntimeMs": 69226, + "measuredRuntimeMs": 130820, + "budget": { + "status": "bounded", + "maxRuntimeMs": 150000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.server-time-specifications", + "checkCount": 1, + "setupRuntimeMs": 28483, + "criterionRuntimeMs": 112803, + "measuredRuntimeMs": 141286, + "budget": { + "status": "bounded", + "maxRuntimeMs": 300000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.cancellation-accounting-specifications", + "checkCount": 1, + "setupRuntimeMs": 837, + "criterionRuntimeMs": 12497, + "measuredRuntimeMs": 13334, + "budget": { + "status": "bounded", + "maxRuntimeMs": 24000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.catalog-management", + "checkCount": 2, + "setupRuntimeMs": 3423, + "criterionRuntimeMs": 25, + "measuredRuntimeMs": 3448, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.customer-profile", + "checkCount": 1, + "setupRuntimeMs": 548, + "criterionRuntimeMs": 5072, + "measuredRuntimeMs": 5620, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.faceted-search", + "checkCount": 2, + "setupRuntimeMs": 43515, + "criterionRuntimeMs": 25609, + "measuredRuntimeMs": 69124, + "budget": { + "status": "bounded", + "maxRuntimeMs": 141000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.fulfilment-queue", + "checkCount": 2, + "setupRuntimeMs": 1470, + "criterionRuntimeMs": 27283, + "measuredRuntimeMs": 28753, + "budget": { + "status": "bounded", + "maxRuntimeMs": 76000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.inventory-conservation-specifications", + "checkCount": 5, + "setupRuntimeMs": 2790, + "criterionRuntimeMs": 64475, + "measuredRuntimeMs": 67265, + "budget": { + "status": "bounded", + "maxRuntimeMs": 138000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.managed-support", + "checkCount": 1, + "setupRuntimeMs": 1085, + "criterionRuntimeMs": 6103, + "measuredRuntimeMs": 7188, + "budget": { + "status": "bounded", + "maxRuntimeMs": 55000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.notification-preferences", + "checkCount": 1, + "setupRuntimeMs": 792, + "criterionRuntimeMs": 5108, + "measuredRuntimeMs": 5900, + "budget": { + "status": "bounded", + "maxRuntimeMs": 40000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.operations-access-specifications", + "checkCount": 3, + "setupRuntimeMs": 10072, + "criterionRuntimeMs": 38249, + "measuredRuntimeMs": 48321, + "budget": { + "status": "bounded", + "maxRuntimeMs": 98000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.promotion-rules", + "checkCount": 1, + "setupRuntimeMs": 633, + "criterionRuntimeMs": 453, + "measuredRuntimeMs": 1086, + "budget": { + "status": "bounded", + "maxRuntimeMs": 45000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.review-access-specifications", + "checkCount": 1, + "setupRuntimeMs": 23869, + "criterionRuntimeMs": 6821, + "measuredRuntimeMs": 30690, + "budget": { + "status": "bounded", + "maxRuntimeMs": 62000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.staff-access", + "checkCount": 1, + "setupRuntimeMs": 1, + "criterionRuntimeMs": 890, + "measuredRuntimeMs": 891, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.staff-roles", + "checkCount": 1, + "setupRuntimeMs": 681, + "criterionRuntimeMs": 34, + "measuredRuntimeMs": 715, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.stock-alerts", + "checkCount": 1, + "setupRuntimeMs": 5143, + "criterionRuntimeMs": 11451, + "measuredRuntimeMs": 16594, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.support-history", + "checkCount": 1, + "setupRuntimeMs": 1056, + "criterionRuntimeMs": 1143, + "measuredRuntimeMs": 2199, + "budget": { + "status": "bounded", + "maxRuntimeMs": 50000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.support-intake", + "checkCount": 1, + "setupRuntimeMs": 0, + "criterionRuntimeMs": 533, + "measuredRuntimeMs": 533, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.support-triage", + "checkCount": 3, + "setupRuntimeMs": 888, + "criterionRuntimeMs": 10137, + "measuredRuntimeMs": 11025, + "budget": { + "status": "bounded", + "maxRuntimeMs": 45000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.access-control", + "checkCount": 21, + "setupRuntimeMs": 30749, + "criterionRuntimeMs": 219503, + "measuredRuntimeMs": 250252, + "budget": { + "status": "bounded", + "maxRuntimeMs": 464000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.concurrency-safety", + "checkCount": 6, + "setupRuntimeMs": 30824, + "criterionRuntimeMs": 72236, + "measuredRuntimeMs": 103060, + "budget": { + "status": "bounded", + "maxRuntimeMs": 125000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.external-data-sync", + "checkCount": 3, + "setupRuntimeMs": 616, + "criterionRuntimeMs": 29325, + "measuredRuntimeMs": 29941, + "budget": { + "status": "bounded", + "maxRuntimeMs": 105000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.live-state", + "checkCount": 11, + "setupRuntimeMs": 81112, + "criterionRuntimeMs": 9419, + "measuredRuntimeMs": 90531, + "budget": { + "status": "bounded", + "maxRuntimeMs": 184000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.search-ordering", + "checkCount": 1, + "setupRuntimeMs": 21759, + "criterionRuntimeMs": 5199, + "measuredRuntimeMs": 26958, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.state-durability", + "checkCount": 10, + "setupRuntimeMs": 126081, + "criterionRuntimeMs": 74760, + "measuredRuntimeMs": 200841, + "budget": { + "status": "bounded", + "maxRuntimeMs": 768000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.transactional-integrity", + "checkCount": 6, + "setupRuntimeMs": 45207, + "criterionRuntimeMs": 38605, + "measuredRuntimeMs": 83812, + "budget": { + "status": "bounded", + "maxRuntimeMs": 100000 + }, + "exceeded": false + } + ] + }, + "mutations": { + "caught": 112, + "total": 112 + }, + "baselineDurationMs": 2240281, + "baselineOutput": "ecommerce-l3-add0647be965-mongodb-mutation.runs/r1", + "baselineHarnessSha256Before": "d423f94e24aae42fa30fcd169e387eeddf15f50c35cebdb4b461044b98e466f8", + "baselineHarnessSha256After": "d423f94e24aae42fa30fcd169e387eeddf15f50c35cebdb4b461044b98e466f8", + "workers": [ + { + "index": 0, + "runIndex": 0, + "artifact": "ecommerce-l3-add0647be965-mongodb-mutation.runs/r1-workers/w1.json", + "mutationIds": [ + "staff-admin-access-survives-role-removal", + "signed-out-visitor-purchase-is-accepted", + "live-review-average-uses-an-extra-divisor", + "unpurchased-review-is-accepted", + "cancel-does-not-restore-stock-fresh-client", + "progression-customer-sees-fulfilment-content", + "catalog-search-requires-exact-name", + "completed-restock-is-replayed", + "profile-read-is-not-owner-scoped", + "promotion-save-drops-bounded-values", + "stock-alert-repeats-while-in-stock", + "direct-purchase-is-attributed-to-another-account", + "support-history-rows-are-hidden", + "queue-ignores-live-fulfilment-updates" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-add0647be965-mongodb-mutation.runs/r1-workers/w1.stdout.log", + "stderr": "ecommerce-l3-add0647be965-mongodb-mutation.runs/r1-workers/w1.stderr.log" + } + }, + { + "index": 1, + "runIndex": 1, + "artifact": "ecommerce-l3-add0647be965-mongodb-mutation.runs/r1-workers/w2.json", + "mutationIds": [ + "shipping-counts-sale-twice", + "espresso-stock-row-ignores-live-updates", + "warehouse-view-omits-one-location", + "purchased-review-ui-does-not-submit", + "cancel-restores-stock-but-keeps-pending-status", + "transfer-debits-source-without-crediting-existing-destination", + "catalog-price-is-offset", + "scheduled-restock-countdown-is-fixed", + "faceted-search-ignores-category", + "customer-can-create-promotion", + "stock-alerts-are-not-owner-scoped", + "concurrent-cart-add-does-not-increment", + "authorized-restock-does-not-change-stock", + "low-stock-boundary-excludes-ten-live" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-add0647be965-mongodb-mutation.runs/r1-workers/w2.stdout.log", + "stderr": "ecommerce-l3-add0647be965-mongodb-mutation.runs/r1-workers/w2.stderr.log" + } + }, + { + "index": 2, + "runIndex": 2, + "artifact": "ecommerce-l3-add0647be965-mongodb-mutation.runs/r1-workers/w3.json", + "mutationIds": [ + "signup-does-not-expose-created-account", + "restock-race-records-wrong-order-total", + "unauthenticated-purchase-defaults-to-admin", + "external-stock-polling-disabled", + "cancelled-order-remains-in-revenue-feature", + "recommendations-ignore-pending-purchases", + "staff-can-see-admin-navigation", + "due-restock-does-not-change-stock", + "active-search-uses-purchase-ranking", + "staff-signin-loses-staff-role", + "support-history-is-lost-on-server-restart", + "checkout-claim-is-not-atomic", + "initial-dashboard-load-omits-low-stock", + "live-admin-updates-keep-stale-category-totals" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-add0647be965-mongodb-mutation.runs/r1-workers/w3.stdout.log", + "stderr": "ecommerce-l3-add0647be965-mongodb-mutation.runs/r1-workers/w3.stderr.log" + } + }, + { + "index": 3, + "runIndex": 3, + "artifact": "ecommerce-l3-add0647be965-mongodb-mutation.runs/r1-workers/w4.json", + "mutationIds": [ + "duplicate-signup-reports-success", + "purchase-order-uses-zero-price", + "direct-purchase-total-ignores-store-price", + "server-restart-disables-catalog-recovery", + "cancelled-order-remains-in-revenue-invariant", + "purchases-do-not-affect-best-sellers", + "staff-can-use-direct-restock", + "cancelled-restock-remains-pending", + "pagination-repeats-first-page", + "customer-signin-gains-staff-role", + "support-history-is-not-owner-scoped", + "last-unit-allows-negative-stock", + "category-totals-skip-the-newest-order", + "overdraw-transfer-is-accepted" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-add0647be965-mongodb-mutation.runs/r1-workers/w4.stdout.log", + "stderr": "ecommerce-l3-add0647be965-mongodb-mutation.runs/r1-workers/w4.stderr.log" + } + }, + { + "index": 4, + "runIndex": 4, + "artifact": "ecommerce-l3-add0647be965-mongodb-mutation.runs/r1-workers/w5.json", + "mutationIds": [ + "signin-skips-password-verification", + "reload-hydrates-an-empty-cart", + "cart-hydration-loses-account-state", + "reconnect-generation-ignores-current-catalog", + "operator-authorization-allows-customer-transfer", + "queue-warehouse-reports-west", + "restock-adds-the-wrong-quantity", + "server-time-restock-never-completes", + "managed-support-live-refresh-keeps-stale-tickets", + "role-assignment-drops-role", + "support-intake-returns-no-reference", + "purchase-read-write-loses-concurrent-stock", + "profile-summary-frozen-at-open", + "transfer-totals-omit-destination-credit-live" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-add0647be965-mongodb-mutation.runs/r1-workers/w5.stdout.log", + "stderr": "ecommerce-l3-add0647be965-mongodb-mutation.runs/r1-workers/w5.stderr.log" + } + }, + { + "index": 5, + "runIndex": 5, + "artifact": "ecommerce-l3-add0647be965-mongodb-mutation.runs/r1-workers/w6.json", + "mutationIds": [ + "signout-keeps-current-account", + "shared-cart-live-events-ignored", + "reconnect-hydration-loses-account-state", + "open-review-list-ignores-live-update", + "customer-can-ship-order-direct-1-1", + "cart-repeat-does-not-increment", + "transfer-creates-stock-during-race", + "catalog-product-name-is-not-published", + "managed-support-allows-another-customer", + "staff-role-write-precedes-denial", + "support-triage-discards-updates", + "purchase-does-not-reduce-warehouse-stock", + "support-replies-present-at-open-are-hidden", + "support-history-leaks-to-signed-out-visitors" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-add0647be965-mongodb-mutation.runs/r1-workers/w6.stdout.log", + "stderr": "ecommerce-l3-add0647be965-mongodb-mutation.runs/r1-workers/w6.stderr.log" + } + }, + { + "index": 6, + "runIndex": 6, + "artifact": "ecommerce-l3-add0647be965-mongodb-mutation.runs/r1-workers/w7.json", + "mutationIds": [ + "session-token-not-persisted", + "review-comment-is-not-persisted", + "order-history-is-not-owner-scoped", + "cancel-does-not-restore-stock-feature", + "customer-can-cancel-foreign-order-1-1", + "checkout-leaves-cart-claimed", + "customer-can-cancel-scheduled-restock", + "catalog-variants-are-discarded", + "notification-preference-is-not-saved", + "staff-can-assign-roles", + "cart-add-uses-another-account-cart", + "restock-does-not-increase-stock", + "notification-toggle-frozen-at-open", + "checkout-crash-integrity" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-add0647be965-mongodb-mutation.runs/r1-workers/w7.stdout.log", + "stderr": "ecommerce-l3-add0647be965-mongodb-mutation.runs/r1-workers/w7.stderr.log" + } + }, + { + "index": 7, + "runIndex": 7, + "artifact": "ecommerce-l3-add0647be965-mongodb-mutation.runs/r1-workers/w8.json", + "mutationIds": [ + "purchase-counts-never-affect-ranking", + "repeat-review-uses-a-new-owner-key", + "revenue-aggregation-ignores-order-totals", + "cancellation-accounting-loses-stock-restoration", + "ship-acknowledges-without-changing-status", + "catalog-initial-ranking-is-reversed", + "scheduled-restock-never-becomes-due-after-restart", + "profile-data-is-lost-on-server-restart", + "notification-preference-is-not-owner-scoped", + "stock-alert-delivery-is-suppressed", + "negative-cart-quantity-is-accepted", + "direct-review-access-is-not-checked", + "role-editor-snaps-back-to-stored-role", + "checkout-crash-durability" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-add0647be965-mongodb-mutation.runs/r1-workers/w8.stdout.log", + "stderr": "ecommerce-l3-add0647be965-mongodb-mutation.runs/r1-workers/w8.stderr.log" + } + } + ] + } + ], + "stable": true, + "sameImage": true, + "sameHarness": true, + "harnessSha256": "d423f94e24aae42fa30fcd169e387eeddf15f50c35cebdb4b461044b98e466f8", + "qualifiedCheckKeys": [ + "ecommerce.feature.accounts.accounts.1a", + "ecommerce.feature.accounts.accounts.1b", + "ecommerce.feature.accounts.accounts.1c", + "ecommerce.feature.accounts.accounts.1d", + "ecommerce.feature.cart-checkout.cart.4a", + "ecommerce.feature.cart-checkout.cart.4d", + "ecommerce.feature.catalog.catalog-ranking.2b", + "ecommerce.feature.catalog.catalog-search.2d", + "ecommerce.feature.catalog.catalog-values.2a", + "ecommerce.feature.purchasing.purchase-order.3c", + "ecommerce.feature.reviews.reviews.6a", + "ecommerce.feature.warehouse-admin.admin-write.103a", + "ecommerce.feature.warehouse-admin.warehouse-view.7b", + "ecommerce.inventory-operations.operational-views.5c", + "ecommerce.inventory-operations.operational-views.5d", + "ecommerce.inventory-operations.operational-views.5e", + "ecommerce.inventory-operations.operational-views.5f", + "ecommerce.inventory-operations.shipping-accounting.202e", + "ecommerce.inventory-operations.stock-conservation.202a", + "ecommerce.inventory-operations.stock-conservation.202b", + "ecommerce.inventory-operations.stock-conservation.202c", + "ecommerce.inventory-operations.stock-conservation.202d", + "ecommerce.inventory-operations.warehouse-transfer.2a", + "ecommerce.l3.deferred-access.scheduled-work-access.317a", + "ecommerce.l3.deferred-durability.restart-survival.311a", + "ecommerce.l3.deferred-integrity.exactly-once.311a", + "ecommerce.l3.scheduled-restocks.scheduled-restocks.302a", + "ecommerce.l3.scheduled-restocks.scheduled-restocks.305a", + "ecommerce.l3.scheduled-restocks.scheduled-restocks.306a", + "ecommerce.l3.server-time.server-time.312a", + "ecommerce.operations-access.fulfilment-queue.1b", + "ecommerce.operations-access.fulfilment-queue.1c", + "ecommerce.operations-access.operator-authorization.201a", + "ecommerce.operations-access.operator-authorization.201c", + "ecommerce.operations-access.order-owner.204a", + "ecommerce.progression.catalog-management.catalog-management.622a", + "ecommerce.progression.catalog-management.catalog-management.622b", + "ecommerce.progression.customer-profile.customer-profile.620c", + "ecommerce.progression.faceted-search.faceted-search.401a", + "ecommerce.progression.faceted-search.faceted-search.402a", + "ecommerce.progression.managed-support.managed-support.613c", + "ecommerce.progression.notification-preferences.notification-preferences.630c", + "ecommerce.progression.promotion-rules.promotion-rule-values.620a", + "ecommerce.progression.review-access-specifications.review-eligibility-direct.618a", + "ecommerce.progression.staff-access.staff-access.601a", + "ecommerce.progression.staff-roles.staff-roles.621c", + "ecommerce.progression.stock-alerts.stock-alert-delivery.631c", + "ecommerce.progression.support-history.support-history.612c", + "ecommerce.progression.support-intake.support-intake.610a", + "ecommerce.progression.support-triage.support-assignment.611a", + "ecommerce.progression.support-triage.support-priority.611b", + "ecommerce.progression.support-triage.support-status.611c", + "ecommerce.returns-pricing.cancellation-and-return.3a", + "ecommerce.returns-pricing.cancellation-and-return.3b", + "ecommerce.returns-pricing.refund-accounting.203a", + "ecommerce.spec.access-control.cart-boundary.109a", + "ecommerce.spec.access-control.cart-boundary.109b", + "ecommerce.spec.access-control.customer-profile-privacy.620b", + "ecommerce.spec.access-control.fulfilment-area-boundary.1d", + "ecommerce.spec.access-control.managed-support-privacy.613b", + "ecommerce.spec.access-control.notification-preferences-privacy.630b", + "ecommerce.spec.access-control.order-ownership.106a", + "ecommerce.spec.access-control.promotion-management-boundary.620b", + "ecommerce.spec.access-control.purchase-attribution.102a", + "ecommerce.spec.access-control.purchase-session.101a", + "ecommerce.spec.access-control.review-eligibility.108a", + "ecommerce.spec.access-control.review-eligibility.108b", + "ecommerce.spec.access-control.signed-out-purchase.3a", + "ecommerce.spec.access-control.staff-area-boundary.601b", + "ecommerce.spec.access-control.staff-role-boundary.621b", + "ecommerce.spec.access-control.staff-role-revocation.621d", + "ecommerce.spec.access-control.stock-alert-privacy.631b", + "ecommerce.spec.access-control.support-history-logout.612d", + "ecommerce.spec.access-control.support-history-privacy.612b", + "ecommerce.spec.access-control.warehouse-area-boundary.7a", + "ecommerce.spec.access-control.warehouse-write-boundary.103b", + "ecommerce.spec.concurrency-safety.duplicate-checkout.203a", + "ecommerce.spec.concurrency-safety.duplicate-checkout.203b", + "ecommerce.spec.concurrency-safety.last-unit.201a", + "ecommerce.spec.concurrency-safety.last-unit.201b", + "ecommerce.spec.concurrency-safety.last-unit.201c", + "ecommerce.spec.concurrency-safety.restock-race.202a", + "ecommerce.spec.external-data-sync.external-stock.901a", + "ecommerce.spec.external-data-sync.external-stock.901c", + "ecommerce.spec.external-data-sync.external-stock.901d", + "ecommerce.spec.live-state.fulfilment-queue.1a", + "ecommerce.spec.live-state.inventory-dashboard.5a", + "ecommerce.spec.live-state.managed-support.613a", + "ecommerce.spec.live-state.open-list.902a", + "ecommerce.spec.live-state.purchase-stock.3b", + "ecommerce.spec.live-state.ranking.2c", + "ecommerce.spec.live-state.rating.6c", + "ecommerce.spec.live-state.sales-dashboard.5b", + "ecommerce.spec.live-state.shared-cart.4c", + "ecommerce.spec.live-state.stock-transfers.2b", + "ecommerce.spec.live-state.warehouse-stock.7c", + "ecommerce.spec.search-ordering.search-ordering.402b", + "ecommerce.spec.state-durability.account-state-recovery.105a", + "ecommerce.spec.state-durability.account-state-recovery.105b", + "ecommerce.spec.state-durability.cart-reload.4b", + "ecommerce.spec.state-durability.checkout-crash-durability.910b", + "ecommerce.spec.state-durability.checkout-crash-integrity.910a", + "ecommerce.spec.state-durability.customer-profile-reload.620a", + "ecommerce.spec.state-durability.notification-preferences-reload.630a", + "ecommerce.spec.state-durability.session-reload.1e", + "ecommerce.spec.state-durability.staff-role-reload.621a", + "ecommerce.spec.state-durability.support-history-reload.612a", + "ecommerce.spec.transactional-integrity.books-balance.107a", + "ecommerce.spec.transactional-integrity.books-balance.107b", + "ecommerce.spec.transactional-integrity.server-price.104a", + "ecommerce.spec.transactional-integrity.stock-alert-deduplication.631a", + "ecommerce.spec.transactional-integrity.stock-transfer-overdraw.2c", + "ecommerce.spec.transactional-integrity.unique-review.6b" + ], + "featureCatalog": { + "contentSha256": "a8c0bf542ec57e0189b99cd3e70a9cea7373c2c83bf4867e11f2c76db329a087", + "id": "ecommerce.questlines" + }, + "diagnostic": false, + "ok": true + } +} diff --git a/tools/stack-bench/qualification-evidence/ecommerce-l3-78ccb6966/mongodb-reference.json b/tools/stack-bench/qualification-evidence/ecommerce-l3-78ccb6966/mongodb-reference.json new file mode 100644 index 00000000000..27c654ccbea --- /dev/null +++ b/tools/stack-bench/qualification-evidence/ecommerce-l3-78ccb6966/mongodb-reference.json @@ -0,0 +1,735 @@ +{ + "artifactSchemaVersion": 2, + "kind": "reference_qualification", + "id": "reference-live-mongodb-20260917171216-30-reference", + "attempt": { + "id": "reference-live-mongodb-20260917171216-30-reference", + "parentId": null + }, + "timestamps": { + "startedAt": "2026-09-17T17:12:16.526Z", + "completedAt": "2026-09-17T18:05:00.353Z" + }, + "identities": { + "engine": { + "id": "stack-bench", + "sha256": "6562a1f38ed757804dc8a6f70ac3c36bb71e7cfd257fbfb4aacd1c30a7412bea" + }, + "recipe": { + "id": "ecommerce.progression-catalog", + "sha256": "add0647be965132c0b9702c5db3ba8265a01b0edc8ca5d820cc152e4ceeb5a89" + }, + "fixture": { + "id": "ecommerce-reference-mongodb", + "sha256": "0d21bbc4b2768f4077a81d676f0d4c87a65067dda8f2c5ffeb2fa9208381dc7e" + }, + "calibration": { + "id": "ecommerce.dependency-l3-calibration", + "sha256": "dc4bf3e29e5d5040becf8fdd846e7d3fd6419a27cb766c8c93a75f19f66c664b" + }, + "experiment": null, + "agentAdapter": null, + "stackAdapter": { + "id": "mongodb", + "sha256": null + }, + "packs": [] + }, + "payload": { + "fixture": "ecommerce-reference-mongodb", + "fixtureSha256": "0d21bbc4b2768f4077a81d676f0d4c87a65067dda8f2c5ffeb2fa9208381dc7e", + "requiredRepetitions": 1, + "isolation": "docker", + "runner": { + "schemaVersion": 1, + "mode": "appliance", + "platform": "linux", + "architecture": "x64", + "hostname": "docker-desktop", + "dockerEngineVersion": "29.6.2", + "dockerOs": "linux", + "dockerArchitecture": "x86_64", + "kernelVersion": "6.6.87.2-microsoft-standard-WSL2", + "cpuCount": 32, + "memoryBytes": 49232842752, + "containersRunning": 10, + "packageRegistry": "http://127.0.0.1:4873/" + }, + "qualificationScope": { + "checksSha256": "64d4f2af43f951e8c70d61ed1e64baf5f376ce3fa6031b1a9d79db2bd48aeaff", + "executableSha256": "dabe88d52dc6d3865f499888d3cbac167623282f053c9fc53523bea13b2aa977", + "kind": "reference", + "mutationSha256": null, + "recipe": { + "contentSha256": "add0647be965132c0b9702c5db3ba8265a01b0edc8ca5d820cc152e4ceeb5a89", + "id": "ecommerce.progression-catalog" + }, + "schemaVersion": 3, + "stack": { + "id": "mongodb", + "reference": { + "id": "ecommerce-reference-mongodb", + "sourceSha256": "0d21bbc4b2768f4077a81d676f0d4c87a65067dda8f2c5ffeb2fa9208381dc7e" + }, + "version": "1.5.0" + }, + "sha256": "a0d801fa82e2134333f1c782af21e134b7201d96968ee75a548ed7a3f7ec2ba1" + }, + "mutationControl": false, + "runs": [ + { + "repetition": 1, + "output": "ecommerce-l3-add0647be965-mongodb-mutation.runs/r1", + "durationMs": 2240281, + "processError": null, + "harnessSha256Before": "d423f94e24aae42fa30fcd169e387eeddf15f50c35cebdb4b461044b98e466f8", + "harnessSha256After": "d423f94e24aae42fa30fcd169e387eeddf15f50c35cebdb4b461044b98e466f8", + "ok": true, + "failures": [], + "runId": "ecommerce-mongodb-run0-20260917171217-ccea8cb0", + "score": "182/182", + "imageId": "sha256:32ff9a9e519ba9d1af2fe72f24622caa8ca7a9f2baf2338c6b1e0435e6ac5455", + "criteria": 113, + "zeroPointCriteria": 0, + "fingerprint": "0d6c57cc6ec1dd08dd5409aa619f28d1aa7c74e27644a80dd2312a0038b978cc", + "outcome": "passed", + "packRuntime": { + "schemaVersion": 1, + "metric": "pack-check-wall-clock-sum-v1", + "packs": [ + { + "id": "ecommerce.feature.accounts", + "checkCount": 4, + "setupRuntimeMs": 1220, + "criterionRuntimeMs": 15190, + "measuredRuntimeMs": 16410, + "budget": { + "status": "bounded", + "maxRuntimeMs": 18000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.cart", + "checkCount": 1, + "setupRuntimeMs": 649, + "criterionRuntimeMs": 6065, + "measuredRuntimeMs": 6714, + "budget": { + "status": "bounded", + "maxRuntimeMs": 42000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.catalog-discovery", + "checkCount": 2, + "setupRuntimeMs": 0, + "criterionRuntimeMs": 1853, + "measuredRuntimeMs": 1853, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.catalog-items", + "checkCount": 1, + "setupRuntimeMs": 0, + "criterionRuntimeMs": 287, + "measuredRuntimeMs": 287, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.checkout", + "checkCount": 1, + "setupRuntimeMs": 649, + "criterionRuntimeMs": 10772, + "measuredRuntimeMs": 11421, + "budget": { + "status": "bounded", + "maxRuntimeMs": 42000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.purchasing", + "checkCount": 1, + "setupRuntimeMs": 347, + "criterionRuntimeMs": 1160, + "measuredRuntimeMs": 1507, + "budget": { + "status": "bounded", + "maxRuntimeMs": 24000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.reviews", + "checkCount": 1, + "setupRuntimeMs": 21635, + "criterionRuntimeMs": 329, + "measuredRuntimeMs": 21964, + "budget": { + "status": "bounded", + "maxRuntimeMs": 22000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.warehouse-admin", + "checkCount": 2, + "setupRuntimeMs": 1645, + "criterionRuntimeMs": 4325, + "measuredRuntimeMs": 5970, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.inventory-dashboard", + "checkCount": 1, + "setupRuntimeMs": 4374, + "criterionRuntimeMs": 8, + "measuredRuntimeMs": 4382, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.order-cancellation-features", + "checkCount": 2, + "setupRuntimeMs": 1074, + "criterionRuntimeMs": 16359, + "measuredRuntimeMs": 17433, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.recommendations", + "checkCount": 1, + "setupRuntimeMs": 343, + "criterionRuntimeMs": 5170, + "measuredRuntimeMs": 5513, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.sales-dashboard", + "checkCount": 2, + "setupRuntimeMs": 2288, + "criterionRuntimeMs": 4999, + "measuredRuntimeMs": 7287, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.stock-transfers-features", + "checkCount": 1, + "setupRuntimeMs": 508, + "criterionRuntimeMs": 2627, + "measuredRuntimeMs": 3135, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.deferred-access-specifications", + "checkCount": 1, + "setupRuntimeMs": 20956, + "criterionRuntimeMs": 4235, + "measuredRuntimeMs": 25191, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.deferred-durability-specifications", + "checkCount": 1, + "setupRuntimeMs": 128627, + "criterionRuntimeMs": 39135, + "measuredRuntimeMs": 167762, + "budget": { + "status": "bounded", + "maxRuntimeMs": 720000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.deferred-integrity-specifications", + "checkCount": 1, + "setupRuntimeMs": 42964, + "criterionRuntimeMs": 39193, + "measuredRuntimeMs": 82157, + "budget": { + "status": "bounded", + "maxRuntimeMs": 400000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.scheduled-restocks-features", + "checkCount": 3, + "setupRuntimeMs": 61594, + "criterionRuntimeMs": 69226, + "measuredRuntimeMs": 130820, + "budget": { + "status": "bounded", + "maxRuntimeMs": 150000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.server-time-specifications", + "checkCount": 1, + "setupRuntimeMs": 28483, + "criterionRuntimeMs": 112803, + "measuredRuntimeMs": 141286, + "budget": { + "status": "bounded", + "maxRuntimeMs": 300000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.cancellation-accounting-specifications", + "checkCount": 1, + "setupRuntimeMs": 837, + "criterionRuntimeMs": 12497, + "measuredRuntimeMs": 13334, + "budget": { + "status": "bounded", + "maxRuntimeMs": 24000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.catalog-management", + "checkCount": 2, + "setupRuntimeMs": 3423, + "criterionRuntimeMs": 25, + "measuredRuntimeMs": 3448, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.customer-profile", + "checkCount": 1, + "setupRuntimeMs": 548, + "criterionRuntimeMs": 5072, + "measuredRuntimeMs": 5620, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.faceted-search", + "checkCount": 2, + "setupRuntimeMs": 43515, + "criterionRuntimeMs": 25609, + "measuredRuntimeMs": 69124, + "budget": { + "status": "bounded", + "maxRuntimeMs": 141000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.fulfilment-queue", + "checkCount": 2, + "setupRuntimeMs": 1470, + "criterionRuntimeMs": 27283, + "measuredRuntimeMs": 28753, + "budget": { + "status": "bounded", + "maxRuntimeMs": 76000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.inventory-conservation-specifications", + "checkCount": 5, + "setupRuntimeMs": 2790, + "criterionRuntimeMs": 64475, + "measuredRuntimeMs": 67265, + "budget": { + "status": "bounded", + "maxRuntimeMs": 138000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.managed-support", + "checkCount": 1, + "setupRuntimeMs": 1085, + "criterionRuntimeMs": 6103, + "measuredRuntimeMs": 7188, + "budget": { + "status": "bounded", + "maxRuntimeMs": 55000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.notification-preferences", + "checkCount": 1, + "setupRuntimeMs": 792, + "criterionRuntimeMs": 5108, + "measuredRuntimeMs": 5900, + "budget": { + "status": "bounded", + "maxRuntimeMs": 40000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.operations-access-specifications", + "checkCount": 3, + "setupRuntimeMs": 10072, + "criterionRuntimeMs": 38249, + "measuredRuntimeMs": 48321, + "budget": { + "status": "bounded", + "maxRuntimeMs": 98000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.promotion-rules", + "checkCount": 1, + "setupRuntimeMs": 633, + "criterionRuntimeMs": 453, + "measuredRuntimeMs": 1086, + "budget": { + "status": "bounded", + "maxRuntimeMs": 45000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.review-access-specifications", + "checkCount": 1, + "setupRuntimeMs": 23869, + "criterionRuntimeMs": 6821, + "measuredRuntimeMs": 30690, + "budget": { + "status": "bounded", + "maxRuntimeMs": 62000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.staff-access", + "checkCount": 1, + "setupRuntimeMs": 1, + "criterionRuntimeMs": 890, + "measuredRuntimeMs": 891, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.staff-roles", + "checkCount": 1, + "setupRuntimeMs": 681, + "criterionRuntimeMs": 34, + "measuredRuntimeMs": 715, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.stock-alerts", + "checkCount": 1, + "setupRuntimeMs": 5143, + "criterionRuntimeMs": 11451, + "measuredRuntimeMs": 16594, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.support-history", + "checkCount": 1, + "setupRuntimeMs": 1056, + "criterionRuntimeMs": 1143, + "measuredRuntimeMs": 2199, + "budget": { + "status": "bounded", + "maxRuntimeMs": 50000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.support-intake", + "checkCount": 1, + "setupRuntimeMs": 0, + "criterionRuntimeMs": 533, + "measuredRuntimeMs": 533, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.support-triage", + "checkCount": 3, + "setupRuntimeMs": 888, + "criterionRuntimeMs": 10137, + "measuredRuntimeMs": 11025, + "budget": { + "status": "bounded", + "maxRuntimeMs": 45000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.access-control", + "checkCount": 21, + "setupRuntimeMs": 30749, + "criterionRuntimeMs": 219503, + "measuredRuntimeMs": 250252, + "budget": { + "status": "bounded", + "maxRuntimeMs": 464000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.concurrency-safety", + "checkCount": 6, + "setupRuntimeMs": 30824, + "criterionRuntimeMs": 72236, + "measuredRuntimeMs": 103060, + "budget": { + "status": "bounded", + "maxRuntimeMs": 125000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.external-data-sync", + "checkCount": 3, + "setupRuntimeMs": 616, + "criterionRuntimeMs": 29325, + "measuredRuntimeMs": 29941, + "budget": { + "status": "bounded", + "maxRuntimeMs": 105000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.live-state", + "checkCount": 11, + "setupRuntimeMs": 81112, + "criterionRuntimeMs": 9419, + "measuredRuntimeMs": 90531, + "budget": { + "status": "bounded", + "maxRuntimeMs": 184000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.search-ordering", + "checkCount": 1, + "setupRuntimeMs": 21759, + "criterionRuntimeMs": 5199, + "measuredRuntimeMs": 26958, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.state-durability", + "checkCount": 10, + "setupRuntimeMs": 126081, + "criterionRuntimeMs": 74760, + "measuredRuntimeMs": 200841, + "budget": { + "status": "bounded", + "maxRuntimeMs": 768000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.transactional-integrity", + "checkCount": 6, + "setupRuntimeMs": 45207, + "criterionRuntimeMs": 38605, + "measuredRuntimeMs": 83812, + "budget": { + "status": "bounded", + "maxRuntimeMs": 100000 + }, + "exceeded": false + } + ] + }, + "mutations": null + } + ], + "stable": true, + "sameImage": true, + "sameHarness": true, + "harnessSha256": "d423f94e24aae42fa30fcd169e387eeddf15f50c35cebdb4b461044b98e466f8", + "qualifiedCheckKeys": [ + "ecommerce.feature.accounts.accounts.1a", + "ecommerce.feature.accounts.accounts.1b", + "ecommerce.feature.accounts.accounts.1c", + "ecommerce.feature.accounts.accounts.1d", + "ecommerce.feature.cart-checkout.cart.4a", + "ecommerce.feature.cart-checkout.cart.4d", + "ecommerce.feature.catalog.catalog-ranking.2b", + "ecommerce.feature.catalog.catalog-search.2d", + "ecommerce.feature.catalog.catalog-values.2a", + "ecommerce.feature.purchasing.purchase-order.3c", + "ecommerce.feature.reviews.reviews.6a", + "ecommerce.feature.warehouse-admin.admin-write.103a", + "ecommerce.feature.warehouse-admin.warehouse-view.7b", + "ecommerce.inventory-operations.operational-views.5c", + "ecommerce.inventory-operations.operational-views.5d", + "ecommerce.inventory-operations.operational-views.5e", + "ecommerce.inventory-operations.operational-views.5f", + "ecommerce.inventory-operations.shipping-accounting.202e", + "ecommerce.inventory-operations.stock-conservation.202a", + "ecommerce.inventory-operations.stock-conservation.202b", + "ecommerce.inventory-operations.stock-conservation.202c", + "ecommerce.inventory-operations.stock-conservation.202d", + "ecommerce.inventory-operations.warehouse-transfer.2a", + "ecommerce.l3.deferred-access.scheduled-work-access.317a", + "ecommerce.l3.deferred-durability.restart-survival.311a", + "ecommerce.l3.deferred-integrity.exactly-once.311a", + "ecommerce.l3.scheduled-restocks.scheduled-restocks.302a", + "ecommerce.l3.scheduled-restocks.scheduled-restocks.305a", + "ecommerce.l3.scheduled-restocks.scheduled-restocks.306a", + "ecommerce.l3.server-time.server-time.312a", + "ecommerce.operations-access.fulfilment-queue.1b", + "ecommerce.operations-access.fulfilment-queue.1c", + "ecommerce.operations-access.operator-authorization.201a", + "ecommerce.operations-access.operator-authorization.201c", + "ecommerce.operations-access.order-owner.204a", + "ecommerce.progression.catalog-management.catalog-management.622a", + "ecommerce.progression.catalog-management.catalog-management.622b", + "ecommerce.progression.customer-profile.customer-profile.620c", + "ecommerce.progression.faceted-search.faceted-search.401a", + "ecommerce.progression.faceted-search.faceted-search.402a", + "ecommerce.progression.managed-support.managed-support.613c", + "ecommerce.progression.notification-preferences.notification-preferences.630c", + "ecommerce.progression.promotion-rules.promotion-rule-values.620a", + "ecommerce.progression.review-access-specifications.review-eligibility-direct.618a", + "ecommerce.progression.staff-access.staff-access.601a", + "ecommerce.progression.staff-roles.staff-roles.621c", + "ecommerce.progression.stock-alerts.stock-alert-delivery.631c", + "ecommerce.progression.support-history.support-history.612c", + "ecommerce.progression.support-intake.support-intake.610a", + "ecommerce.progression.support-triage.support-assignment.611a", + "ecommerce.progression.support-triage.support-priority.611b", + "ecommerce.progression.support-triage.support-status.611c", + "ecommerce.returns-pricing.cancellation-and-return.3a", + "ecommerce.returns-pricing.cancellation-and-return.3b", + "ecommerce.returns-pricing.refund-accounting.203a", + "ecommerce.spec.access-control.cart-boundary.109a", + "ecommerce.spec.access-control.cart-boundary.109b", + "ecommerce.spec.access-control.customer-profile-privacy.620b", + "ecommerce.spec.access-control.fulfilment-area-boundary.1d", + "ecommerce.spec.access-control.managed-support-privacy.613b", + "ecommerce.spec.access-control.notification-preferences-privacy.630b", + "ecommerce.spec.access-control.order-ownership.106a", + "ecommerce.spec.access-control.promotion-management-boundary.620b", + "ecommerce.spec.access-control.purchase-attribution.102a", + "ecommerce.spec.access-control.purchase-session.101a", + "ecommerce.spec.access-control.review-eligibility.108a", + "ecommerce.spec.access-control.review-eligibility.108b", + "ecommerce.spec.access-control.signed-out-purchase.3a", + "ecommerce.spec.access-control.staff-area-boundary.601b", + "ecommerce.spec.access-control.staff-role-boundary.621b", + "ecommerce.spec.access-control.staff-role-revocation.621d", + "ecommerce.spec.access-control.stock-alert-privacy.631b", + "ecommerce.spec.access-control.support-history-logout.612d", + "ecommerce.spec.access-control.support-history-privacy.612b", + "ecommerce.spec.access-control.warehouse-area-boundary.7a", + "ecommerce.spec.access-control.warehouse-write-boundary.103b", + "ecommerce.spec.concurrency-safety.duplicate-checkout.203a", + "ecommerce.spec.concurrency-safety.duplicate-checkout.203b", + "ecommerce.spec.concurrency-safety.last-unit.201a", + "ecommerce.spec.concurrency-safety.last-unit.201b", + "ecommerce.spec.concurrency-safety.last-unit.201c", + "ecommerce.spec.concurrency-safety.restock-race.202a", + "ecommerce.spec.external-data-sync.external-stock.901a", + "ecommerce.spec.external-data-sync.external-stock.901c", + "ecommerce.spec.external-data-sync.external-stock.901d", + "ecommerce.spec.live-state.fulfilment-queue.1a", + "ecommerce.spec.live-state.inventory-dashboard.5a", + "ecommerce.spec.live-state.managed-support.613a", + "ecommerce.spec.live-state.open-list.902a", + "ecommerce.spec.live-state.purchase-stock.3b", + "ecommerce.spec.live-state.ranking.2c", + "ecommerce.spec.live-state.rating.6c", + "ecommerce.spec.live-state.sales-dashboard.5b", + "ecommerce.spec.live-state.shared-cart.4c", + "ecommerce.spec.live-state.stock-transfers.2b", + "ecommerce.spec.live-state.warehouse-stock.7c", + "ecommerce.spec.search-ordering.search-ordering.402b", + "ecommerce.spec.state-durability.account-state-recovery.105a", + "ecommerce.spec.state-durability.account-state-recovery.105b", + "ecommerce.spec.state-durability.cart-reload.4b", + "ecommerce.spec.state-durability.checkout-crash-durability.910b", + "ecommerce.spec.state-durability.checkout-crash-integrity.910a", + "ecommerce.spec.state-durability.customer-profile-reload.620a", + "ecommerce.spec.state-durability.notification-preferences-reload.630a", + "ecommerce.spec.state-durability.session-reload.1e", + "ecommerce.spec.state-durability.staff-role-reload.621a", + "ecommerce.spec.state-durability.support-history-reload.612a", + "ecommerce.spec.transactional-integrity.books-balance.107a", + "ecommerce.spec.transactional-integrity.books-balance.107b", + "ecommerce.spec.transactional-integrity.server-price.104a", + "ecommerce.spec.transactional-integrity.stock-alert-deduplication.631a", + "ecommerce.spec.transactional-integrity.stock-transfer-overdraw.2c", + "ecommerce.spec.transactional-integrity.unique-review.6b" + ], + "featureCatalog": { + "contentSha256": "a8c0bf542ec57e0189b99cd3e70a9cea7373c2c83bf4867e11f2c76db329a087", + "id": "ecommerce.questlines" + }, + "diagnostic": false, + "ok": true + } +} diff --git a/tools/stack-bench/qualification-evidence/ecommerce-l3-78ccb6966/null.json b/tools/stack-bench/qualification-evidence/ecommerce-l3-78ccb6966/null.json new file mode 100644 index 00000000000..0c633dc61a4 --- /dev/null +++ b/tools/stack-bench/qualification-evidence/ecommerce-l3-78ccb6966/null.json @@ -0,0 +1,1683 @@ +{ + "artifactSchemaVersion": 2, + "kind": "null_control", + "id": "null-control-2026-09-17T17-12-18-722Z", + "attempt": { + "id": "null-control-2026-09-17T17-12-18-722Z", + "parentId": null + }, + "timestamps": { + "startedAt": "2026-09-17T17:12:18.723Z", + "completedAt": "2026-09-17T17:20:02.666Z" + }, + "identities": { + "engine": { + "id": "stack-bench", + "sha256": "6562a1f38ed757804dc8a6f70ac3c36bb71e7cfd257fbfb4aacd1c30a7412bea" + }, + "recipe": { + "id": "ecommerce.progression-catalog", + "sha256": "add0647be965132c0b9702c5db3ba8265a01b0edc8ca5d820cc152e4ceeb5a89" + }, + "fixture": null, + "calibration": { + "id": "ecommerce.dependency-l3-calibration", + "sha256": "dc4bf3e29e5d5040becf8fdd846e7d3fd6419a27cb766c8c93a75f19f66c664b" + }, + "experiment": null, + "agentAdapter": null, + "stackAdapter": null, + "packs": [] + }, + "payload": { + "durationMs": 463943, + "runner": { + "schemaVersion": 1, + "mode": "appliance", + "platform": "linux", + "architecture": "x64", + "hostname": "docker-desktop", + "dockerEngineVersion": "29.6.2", + "dockerOs": "linux", + "dockerArchitecture": "x86_64", + "kernelVersion": "6.6.87.2-microsoft-standard-WSL2", + "cpuCount": 32, + "memoryBytes": 49232842752, + "containersRunning": 21, + "packageRegistry": "http://127.0.0.1:4873/" + }, + "qualificationScope": { + "checksSha256": "64d4f2af43f951e8c70d61ed1e64baf5f376ce3fa6031b1a9d79db2bd48aeaff", + "executableSha256": "1ffa96d08e944d9b6bbb907acb99a0c80c305b341844d503b9e9c4e4819e1381", + "kind": "null", + "mutationSha256": null, + "recipe": { + "contentSha256": "add0647be965132c0b9702c5db3ba8265a01b0edc8ca5d820cc152e4ceeb5a89", + "id": "ecommerce.progression-catalog" + }, + "schemaVersion": 3, + "stack": null, + "sha256": "6829ee810748f13080802c4c67ec17b4f05510a29e765df917b893d479e340bb" + }, + "tracks": [ + "ecommerce" + ], + "ok": true, + "summary": { + "criteria": 113, + "points": 182, + "expectedFailures": { + "criteria": 113, + "points": 182 + }, + "expectedFailureStages": { + "setup": { + "criteria": 106, + "points": 172 + }, + "assertion": { + "criteria": 7, + "points": 10 + } + }, + "vacuousPasses": { + "criteria": 0, + "points": 0 + }, + "oracleGaps": { + "criteria": 0, + "points": 0 + }, + "unscored": { + "criteria": 0, + "passed": 0, + "failed": 0, + "inconclusive": 0 + } + }, + "criteria": [ + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-001", + "scenario": "scenarios/01-account-create.json", + "feature": 1, + "featureName": "Accounts", + "criterion": "1a", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "failed", + "failureStage": "assertion", + "detail": "none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-002", + "scenario": "scenarios/01-account-duplicate.json", + "feature": 1, + "featureName": "Accounts", + "criterion": "1b", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-003", + "scenario": "scenarios/01-account-password.json", + "feature": 1, + "featureName": "Accounts", + "criterion": "1c", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-004", + "scenario": "scenarios/01-account-reload.json", + "feature": 1, + "featureName": "Accounts", + "criterion": "1e", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-005", + "scenario": "scenarios/01-account-signout.json", + "feature": 1, + "featureName": "Accounts", + "criterion": "1d", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-006", + "scenario": "scenarios/01-admin-write-staff.json", + "feature": 103, + "featureName": "Only an administrator can restock", + "criterion": "103a", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-006", + "scenario": "scenarios/01-admin-write-staff.json", + "feature": 103, + "featureName": "Only an administrator can restock", + "criterion": "103b", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-007", + "scenario": "scenarios/01-buying.json", + "feature": 3, + "featureName": "Buying", + "criterion": "3b", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-008", + "scenario": "scenarios/01-cart-boundary.json", + "feature": 109, + "featureName": "A cart is nobody else's business", + "criterion": "109a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-008", + "scenario": "scenarios/01-cart-boundary.json", + "feature": 109, + "featureName": "A cart is nobody else's business", + "criterion": "109b", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-009", + "scenario": "scenarios/01-cart.json", + "feature": 4, + "featureName": "Cart belongs to the account", + "criterion": "4b", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-009", + "scenario": "scenarios/01-cart.json", + "feature": 4, + "featureName": "Cart belongs to the account", + "criterion": "4c", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-010", + "scenario": "scenarios/01-catalog-ranking.json", + "feature": 2, + "featureName": "Public catalog ranking", + "criterion": "2b", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "failed", + "failureStage": "assertion", + "detail": "the item-name control entries are not in the required order" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-011", + "scenario": "scenarios/01-catalog-search.json", + "feature": 2, + "featureName": "Public catalog search", + "criterion": "2d", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "failed", + "failureStage": "assertion", + "detail": "the search-input control did not become available in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-012", + "scenario": "scenarios/01-catalog-values.json", + "feature": 2, + "featureName": "Public catalog values", + "criterion": "2a", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "failed", + "failureStage": "assertion", + "detail": "the item-card control matching \"Air Purifier\" did not appear" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-013", + "scenario": "scenarios/01-core.json", + "feature": 2, + "featureName": "Storefront is public and live", + "criterion": "2c", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-014", + "scenario": "scenarios/01-duplicate-checkout.json", + "feature": 203, + "featureName": "One cart, two tabs, one checkout", + "criterion": "203a", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-014", + "scenario": "scenarios/01-duplicate-checkout.json", + "feature": 203, + "featureName": "One cart, two tabs, one checkout", + "criterion": "203b", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-015", + "scenario": "scenarios/01-external-live-sync.json", + "feature": 901, + "featureName": "An open storefront follows a direct database write", + "criterion": "901a", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: the item-stock control inside the item-card control in the entry matching \"Desk Lamp\" did not appear" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-016", + "scenario": "scenarios/01-external-reconnect-sync.json", + "feature": 901, + "featureName": "A reconnecting storefront catches up to an external write", + "criterion": "901d", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: the item-stock control inside the item-card control in the entry matching \"Desk Lamp\" did not appear" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-018", + "scenario": "scenarios/01-external-server-restart-sync.json", + "feature": 901, + "featureName": "An open storefront catches up after its server restarts", + "criterion": "901c", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: the item-stock control inside the item-card control in the entry matching \"Desk Lamp\" did not appear" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-019", + "scenario": "scenarios/01-last-unit.json", + "feature": 201, + "featureName": "The last unit is sold once", + "criterion": "201a", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-019", + "scenario": "scenarios/01-last-unit.json", + "feature": 201, + "featureName": "The last unit is sold once", + "criterion": "201c", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-019", + "scenario": "scenarios/01-last-unit.json", + "feature": 201, + "featureName": "The last unit is sold once", + "criterion": "201b", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-020", + "scenario": "scenarios/01-order-ownership.json", + "feature": 106, + "featureName": "One customer's orders are not another's", + "criterion": "106a", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-021", + "scenario": "scenarios/01-purchase-attribution.json", + "feature": 102, + "featureName": "Purchases are attributed to whoever made them", + "criterion": "102a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-022", + "scenario": "scenarios/01-purchase-session.json", + "feature": 101, + "featureName": "Purchase requires an account", + "criterion": "101a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-023", + "scenario": "scenarios/01-restock-race.json", + "feature": 202, + "featureName": "A restock during a rush is not lost", + "criterion": "202a", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-024", + "scenario": "scenarios/01-review-eligibility.json", + "feature": 108, + "featureName": "A review is a claim about a purchase", + "criterion": "108a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-024", + "scenario": "scenarios/01-review-eligibility.json", + "feature": 108, + "featureName": "A review is a claim about a purchase", + "criterion": "108b", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-025", + "scenario": "scenarios/01-review-rating-live.json", + "feature": 6, + "featureName": "Reviews", + "criterion": "6c", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-026", + "scenario": "scenarios/01-review-uniqueness.json", + "feature": 6, + "featureName": "Reviews", + "criterion": "6b", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-027", + "scenario": "scenarios/01-review-visibility.json", + "feature": 6, + "featureName": "Reviews", + "criterion": "6a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-028", + "scenario": "scenarios/01-server-price.json", + "feature": 104, + "featureName": "The price is the store's to set", + "criterion": "104a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-029", + "scenario": "scenarios/01-warehouse-admin-staff.json", + "feature": 7, + "featureName": "Admin and warehouses", + "criterion": "7a", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-029", + "scenario": "scenarios/01-warehouse-admin-staff.json", + "feature": 7, + "featureName": "Admin and warehouses", + "criterion": "7b", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-030", + "scenario": "scenarios/01-warehouse-stock-live-staff.json", + "feature": 7, + "featureName": "Warehouse stock stays live", + "criterion": "7c", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-032", + "scenario": "scenarios/02-fulfilment-access.json", + "feature": 1, + "featureName": "Fulfilment area access", + "criterion": "1d", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-033", + "scenario": "scenarios/02-fulfilment-live.json", + "feature": 1, + "featureName": "Live fulfilment queue", + "criterion": "1a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-034", + "scenario": "scenarios/02-fulfilment-ship.json", + "feature": 1, + "featureName": "Ship a pending order", + "criterion": "1c", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-035", + "scenario": "scenarios/02-invariants.json", + "feature": 203, + "featureName": "The books still balance once money can flow backwards", + "criterion": "203a", + "points": 3, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-037", + "scenario": "scenarios/02-low-stock.json", + "feature": 5, + "featureName": "The low-stock view", + "criterion": "5e", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-037", + "scenario": "scenarios/02-low-stock.json", + "feature": 5, + "featureName": "The low-stock view", + "criterion": "5a", + "points": 3, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-038", + "scenario": "scenarios/02-operational-best-sellers.json", + "feature": 5, + "featureName": "Signed-out best sellers", + "criterion": "5d", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-039", + "scenario": "scenarios/02-operational-category-totals.json", + "feature": 5, + "featureName": "Category sales totals", + "criterion": "5f", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-039", + "scenario": "scenarios/02-operational-category-totals.json", + "feature": 5, + "featureName": "Category sales totals", + "criterion": "5b", + "points": 3, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-040", + "scenario": "scenarios/02-operational-recommendations.json", + "feature": 5, + "featureName": "Customer recommendations", + "criterion": "5c", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-041", + "scenario": "scenarios/02-order-cancellation-core.json", + "feature": 3, + "featureName": "Cancel a pending order", + "criterion": "3a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-042", + "scenario": "scenarios/02-order-cancellation-history.json", + "feature": 3, + "featureName": "Cancellation history", + "criterion": "3b", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-044", + "scenario": "scenarios/02-queue-warehouse.json", + "feature": 1, + "featureName": "Fulfilment queue", + "criterion": "1b", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-045", + "scenario": "scenarios/02-self-contained.json", + "feature": 202, + "featureName": "Stock recovery is durable across clients", + "criterion": "202b", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-045", + "scenario": "scenarios/02-self-contained.json", + "feature": 202, + "featureName": "Stock recovery is durable across clients", + "criterion": "202c", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-046", + "scenario": "scenarios/02-server-actions.json", + "feature": 201, + "featureName": "Shipping requires an operator", + "criterion": "201c", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-046", + "scenario": "scenarios/02-server-actions.json", + "feature": 202, + "featureName": "Stock is conserved while operations overlap", + "criterion": "202d", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-046", + "scenario": "scenarios/02-server-actions.json", + "feature": 204, + "featureName": "An order belongs to the person who placed it", + "criterion": "204a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-047", + "scenario": "scenarios/02-strengthened.json", + "feature": 2, + "featureName": "Moving stock between warehouses", + "criterion": "2a", + "points": 3, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-047", + "scenario": "scenarios/02-strengthened.json", + "feature": 201, + "featureName": "Operating the store requires authorization", + "criterion": "201a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-047", + "scenario": "scenarios/02-strengthened.json", + "feature": 202, + "featureName": "Stock is conserved however it moves", + "criterion": "202a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-048", + "scenario": "scenarios/02-transfer-overdraw.json", + "feature": 2, + "featureName": "Moving stock between warehouses", + "criterion": "2c", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-049", + "scenario": "scenarios/02-transfer-totals.json", + "feature": 2, + "featureName": "Warehouse totals", + "criterion": "2b", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-051", + "scenario": "scenarios/03-deferred-access.json", + "feature": 317, + "featureName": "Customers cannot manage scheduled restocks", + "criterion": "317a", + "points": 3, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-052", + "scenario": "scenarios/03-deferred-durability.json", + "feature": 311, + "featureName": "A scheduled restock survives restart", + "criterion": "311a", + "points": 4, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-053", + "scenario": "scenarios/03-deferred-integrity.json", + "feature": 311, + "featureName": "A restock applies once", + "criterion": "311a", + "points": 3, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-056", + "scenario": "scenarios/03-scheduled-restock-apply.json", + "feature": 305, + "featureName": "A due restock applies", + "criterion": "305a", + "points": 3, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-057", + "scenario": "scenarios/03-scheduled-restock-cancel.json", + "feature": 306, + "featureName": "A scheduled restock can be cancelled", + "criterion": "306a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-058", + "scenario": "scenarios/03-scheduled-restocks.json", + "feature": 302, + "featureName": "A restock is pending before it is due", + "criterion": "302a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-059", + "scenario": "scenarios/03-server-time.json", + "feature": 312, + "featureName": "Restart does not run work early", + "criterion": "312a", + "points": 3, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-060", + "scenario": "scenarios/progression-account-state-reconnect.json", + "feature": 105, + "featureName": "An account keeps what belongs to it", + "criterion": "105b", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-061", + "scenario": "scenarios/progression-account-state-reload.json", + "feature": 105, + "featureName": "An account keeps what belongs to it", + "criterion": "105a", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-065", + "scenario": "scenarios/progression-books-balance.json", + "feature": 107, + "featureName": "The books balance", + "criterion": "107a", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-065", + "scenario": "scenarios/progression-books-balance.json", + "feature": 107, + "featureName": "The books balance", + "criterion": "107b", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-068", + "scenario": "scenarios/progression-cart-checkout.json", + "feature": 4, + "featureName": "Account cart and checkout", + "criterion": "4a", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-068", + "scenario": "scenarios/progression-cart-checkout.json", + "feature": 4, + "featureName": "Account cart and checkout", + "criterion": "4d", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-070", + "scenario": "scenarios/progression-catalog-management.json", + "feature": 622, + "featureName": "Catalog management", + "criterion": "622a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-070", + "scenario": "scenarios/progression-catalog-management.json", + "feature": 622, + "featureName": "Catalog management", + "criterion": "622b", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-071", + "scenario": "scenarios/progression-checkout-crash.json", + "feature": 910, + "featureName": "Checkout crash recovery", + "criterion": "910a", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-071", + "scenario": "scenarios/progression-checkout-crash.json", + "feature": 910, + "featureName": "Checkout crash recovery", + "criterion": "910b", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-073", + "scenario": "scenarios/progression-customer-profile.json", + "feature": 620, + "featureName": "Customer profile", + "criterion": "620c", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-073", + "scenario": "scenarios/progression-customer-profile.json", + "feature": 620, + "featureName": "Customer profile", + "criterion": "620a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-073", + "scenario": "scenarios/progression-customer-profile.json", + "feature": 620, + "featureName": "Customer profile", + "criterion": "620b", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-075", + "scenario": "scenarios/progression-faceted-filters.json", + "feature": 401, + "featureName": "Filters compose", + "criterion": "401a", + "points": 3, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: the category-filter control did not become available in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-076", + "scenario": "scenarios/progression-faceted-pagination.json", + "feature": 402, + "featureName": "Pages are stable", + "criterion": "402a", + "points": 3, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: the minimum-price control did not become available in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-077", + "scenario": "scenarios/progression-managed-support-privacy.json", + "feature": 613, + "featureName": "Managed support privacy", + "criterion": "613b", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-078", + "scenario": "scenarios/progression-managed-support-shared.json", + "feature": 613, + "featureName": "Shared managed support case", + "criterion": "613c", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-078", + "scenario": "scenarios/progression-managed-support-shared.json", + "feature": 613, + "featureName": "Shared managed support case", + "criterion": "613a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-079", + "scenario": "scenarios/progression-notification-preferences.json", + "feature": 630, + "featureName": "Account notification preferences", + "criterion": "630c", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-079", + "scenario": "scenarios/progression-notification-preferences.json", + "feature": 630, + "featureName": "Account notification preferences", + "criterion": "630a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-079", + "scenario": "scenarios/progression-notification-preferences.json", + "feature": 630, + "featureName": "Account notification preferences", + "criterion": "630b", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-080", + "scenario": "scenarios/progression-open-list-live.json", + "feature": 902, + "featureName": "An open list stays current", + "criterion": "902a", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-090", + "scenario": "scenarios/progression-promotion-rules.json", + "feature": 620, + "featureName": "Staff-managed promotion rules", + "criterion": "620a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-090", + "scenario": "scenarios/progression-promotion-rules.json", + "feature": 620, + "featureName": "Staff-managed promotion rules", + "criterion": "620b", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-091", + "scenario": "scenarios/progression-purchasing.json", + "feature": 3, + "featureName": "Purchase order history", + "criterion": "3c", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-093", + "scenario": "scenarios/progression-review-access.json", + "feature": 618, + "featureName": "Review access", + "criterion": "618a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-094", + "scenario": "scenarios/progression-search-ordering.json", + "feature": 402, + "featureName": "Purchases preserve search ordering", + "criterion": "402b", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-095", + "scenario": "scenarios/progression-shipping-accounting.json", + "feature": 202, + "featureName": "Shipping preserves completed purchase accounting", + "criterion": "202e", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-096", + "scenario": "scenarios/progression-signed-out-purchase.json", + "feature": 3, + "featureName": "Buying", + "criterion": "3a", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: the item-card control matching \"Keyboard\" did not appear" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-098", + "scenario": "scenarios/progression-staff-access.json", + "feature": 601, + "featureName": "Staff access", + "criterion": "601a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "failed", + "failureStage": "assertion", + "detail": "none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-098", + "scenario": "scenarios/progression-staff-access.json", + "feature": 601, + "featureName": "Staff access", + "criterion": "601b", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "failed", + "failureStage": "assertion", + "detail": "none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-100", + "scenario": "scenarios/progression-staff-roles.json", + "feature": 621, + "featureName": "Staff roles", + "criterion": "621c", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-100", + "scenario": "scenarios/progression-staff-roles.json", + "feature": 621, + "featureName": "Staff roles", + "criterion": "621a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-100", + "scenario": "scenarios/progression-staff-roles.json", + "feature": 621, + "featureName": "Staff roles", + "criterion": "621b", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-100", + "scenario": "scenarios/progression-staff-roles.json", + "feature": 621, + "featureName": "Staff roles", + "criterion": "621d", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-101", + "scenario": "scenarios/progression-stock-alert-delivery.json", + "feature": 631, + "featureName": "Stock alert delivery", + "criterion": "631c", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-102", + "scenario": "scenarios/progression-stock-alerts.json", + "feature": 631, + "featureName": "Private one-time stock alerts", + "criterion": "631a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-102", + "scenario": "scenarios/progression-stock-alerts.json", + "feature": 631, + "featureName": "Private one-time stock alerts", + "criterion": "631b", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-106", + "scenario": "scenarios/progression-support-history.json", + "feature": 612, + "featureName": "Customer support history", + "criterion": "612c", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-106", + "scenario": "scenarios/progression-support-history.json", + "feature": 612, + "featureName": "Customer support history", + "criterion": "612a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-106", + "scenario": "scenarios/progression-support-history.json", + "feature": 612, + "featureName": "Customer support history", + "criterion": "612b", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-106", + "scenario": "scenarios/progression-support-history.json", + "feature": 612, + "featureName": "Customer support history", + "criterion": "612d", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-107", + "scenario": "scenarios/progression-support-intake.json", + "feature": 610, + "featureName": "Support intake", + "criterion": "610a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "failed", + "failureStage": "assertion", + "detail": "the support-link control did not become available in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-112", + "scenario": "scenarios/progression-support-triage.json", + "feature": 611, + "featureName": "Support triage", + "criterion": "611a", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: the support-link control did not become available in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-112", + "scenario": "scenarios/progression-support-triage.json", + "feature": 611, + "featureName": "Support triage", + "criterion": "611b", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: the support-link control did not become available in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-112", + "scenario": "scenarios/progression-support-triage.json", + "feature": 611, + "featureName": "Support triage", + "criterion": "611c", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: the support-link control did not become available in time" + } + ] + } +} diff --git a/tools/stack-bench/qualification-evidence/ecommerce-l3-78ccb6966/postgres-mutation.json b/tools/stack-bench/qualification-evidence/ecommerce-l3-78ccb6966/postgres-mutation.json new file mode 100644 index 00000000000..ea5f355fa75 --- /dev/null +++ b/tools/stack-bench/qualification-evidence/ecommerce-l3-78ccb6966/postgres-mutation.json @@ -0,0 +1,952 @@ +{ + "artifactSchemaVersion": 2, + "kind": "reference_qualification", + "id": "reference-live-postgres-20260917171217-30", + "attempt": { + "id": "reference-live-postgres-20260917171217-30", + "parentId": null + }, + "timestamps": { + "startedAt": "2026-09-17T17:12:17.478Z", + "completedAt": "2026-09-17T17:54:45.076Z" + }, + "identities": { + "engine": { + "id": "stack-bench", + "sha256": "6562a1f38ed757804dc8a6f70ac3c36bb71e7cfd257fbfb4aacd1c30a7412bea" + }, + "recipe": { + "id": "ecommerce.progression-catalog", + "sha256": "add0647be965132c0b9702c5db3ba8265a01b0edc8ca5d820cc152e4ceeb5a89" + }, + "fixture": { + "id": "ecommerce-reference-postgres", + "sha256": "f3906fa01050f00a0ed76c69c256a6b0013bbf72eb72c03aa92d79e47b71c2b8" + }, + "calibration": { + "id": "ecommerce.dependency-l3-calibration", + "sha256": "dc4bf3e29e5d5040becf8fdd846e7d3fd6419a27cb766c8c93a75f19f66c664b" + }, + "experiment": null, + "agentAdapter": null, + "stackAdapter": { + "id": "postgres", + "sha256": null + }, + "packs": [] + }, + "payload": { + "fixture": "ecommerce-reference-postgres", + "fixtureSha256": "f3906fa01050f00a0ed76c69c256a6b0013bbf72eb72c03aa92d79e47b71c2b8", + "requiredRepetitions": 1, + "isolation": "docker", + "runner": { + "schemaVersion": 1, + "mode": "appliance", + "platform": "linux", + "architecture": "x64", + "hostname": "docker-desktop", + "dockerEngineVersion": "29.6.2", + "dockerOs": "linux", + "dockerArchitecture": "x86_64", + "kernelVersion": "6.6.87.2-microsoft-standard-WSL2", + "cpuCount": 32, + "memoryBytes": 49232842752, + "containersRunning": 11, + "packageRegistry": "http://127.0.0.1:4873/" + }, + "qualificationScope": { + "checksSha256": "64d4f2af43f951e8c70d61ed1e64baf5f376ce3fa6031b1a9d79db2bd48aeaff", + "executableSha256": "233641c255d195b18bf3717b2e2fbae69a153425806d7fb53709b97d1994eb8d", + "kind": "mutation", + "mutationSha256": "5689f1cb5694920a846a4e9de54d678bb969196d1610cded80b4a107600ec34e", + "recipe": { + "contentSha256": "add0647be965132c0b9702c5db3ba8265a01b0edc8ca5d820cc152e4ceeb5a89", + "id": "ecommerce.progression-catalog" + }, + "schemaVersion": 3, + "stack": { + "id": "postgres", + "reference": { + "id": "ecommerce-reference-postgres", + "sourceSha256": "f3906fa01050f00a0ed76c69c256a6b0013bbf72eb72c03aa92d79e47b71c2b8" + }, + "version": "1.6.0" + }, + "sha256": "b77f4df8a47e3c8578b24dc461d006ee57145dcea9b19c9206a3f4616f546bec" + }, + "mutationControl": true, + "runs": [ + { + "repetition": 1, + "output": "ecommerce-l3-add0647be965-postgres-mutation.runs/r1-workers", + "durationMs": 2547532, + "processError": null, + "harnessSha256Before": "d423f94e24aae42fa30fcd169e387eeddf15f50c35cebdb4b461044b98e466f8", + "harnessSha256After": "d423f94e24aae42fa30fcd169e387eeddf15f50c35cebdb4b461044b98e466f8", + "ok": true, + "failures": [], + "runId": "reference-live-postgres-20260917171217-30", + "score": "182/182", + "imageId": "sha256:32ff9a9e519ba9d1af2fe72f24622caa8ca7a9f2baf2338c6b1e0435e6ac5455", + "criteria": 113, + "zeroPointCriteria": 0, + "fingerprint": "0d6c57cc6ec1dd08dd5409aa619f28d1aa7c74e27644a80dd2312a0038b978cc", + "outcome": "passed", + "packRuntime": { + "schemaVersion": 1, + "metric": "pack-check-wall-clock-sum-v1", + "packs": [ + { + "id": "ecommerce.feature.accounts", + "checkCount": 4, + "setupRuntimeMs": 1045, + "criterionRuntimeMs": 15156, + "measuredRuntimeMs": 16201, + "budget": { + "status": "bounded", + "maxRuntimeMs": 18000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.cart", + "checkCount": 1, + "setupRuntimeMs": 458, + "criterionRuntimeMs": 6081, + "measuredRuntimeMs": 6539, + "budget": { + "status": "bounded", + "maxRuntimeMs": 42000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.catalog-discovery", + "checkCount": 2, + "setupRuntimeMs": 0, + "criterionRuntimeMs": 1855, + "measuredRuntimeMs": 1855, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.catalog-items", + "checkCount": 1, + "setupRuntimeMs": 0, + "criterionRuntimeMs": 229, + "measuredRuntimeMs": 229, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.checkout", + "checkCount": 1, + "setupRuntimeMs": 458, + "criterionRuntimeMs": 5987, + "measuredRuntimeMs": 6445, + "budget": { + "status": "bounded", + "maxRuntimeMs": 42000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.purchasing", + "checkCount": 1, + "setupRuntimeMs": 336, + "criterionRuntimeMs": 1164, + "measuredRuntimeMs": 1500, + "budget": { + "status": "bounded", + "maxRuntimeMs": 24000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.reviews", + "checkCount": 1, + "setupRuntimeMs": 1742, + "criterionRuntimeMs": 363, + "measuredRuntimeMs": 2105, + "budget": { + "status": "bounded", + "maxRuntimeMs": 22000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.warehouse-admin", + "checkCount": 2, + "setupRuntimeMs": 1311, + "criterionRuntimeMs": 4333, + "measuredRuntimeMs": 5644, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.inventory-dashboard", + "checkCount": 1, + "setupRuntimeMs": 3442, + "criterionRuntimeMs": 8, + "measuredRuntimeMs": 3450, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.order-cancellation-features", + "checkCount": 2, + "setupRuntimeMs": 1001, + "criterionRuntimeMs": 11189, + "measuredRuntimeMs": 12190, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.recommendations", + "checkCount": 1, + "setupRuntimeMs": 344, + "criterionRuntimeMs": 5223, + "measuredRuntimeMs": 5567, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.sales-dashboard", + "checkCount": 2, + "setupRuntimeMs": 2047, + "criterionRuntimeMs": 4988, + "measuredRuntimeMs": 7035, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.stock-transfers-features", + "checkCount": 1, + "setupRuntimeMs": 414, + "criterionRuntimeMs": 971, + "measuredRuntimeMs": 1385, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.deferred-access-specifications", + "checkCount": 1, + "setupRuntimeMs": 20950, + "criterionRuntimeMs": 4260, + "measuredRuntimeMs": 25210, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.deferred-durability-specifications", + "checkCount": 1, + "setupRuntimeMs": 126312, + "criterionRuntimeMs": 38980, + "measuredRuntimeMs": 165292, + "budget": { + "status": "bounded", + "maxRuntimeMs": 720000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.deferred-integrity-specifications", + "checkCount": 1, + "setupRuntimeMs": 42271, + "criterionRuntimeMs": 38576, + "measuredRuntimeMs": 80847, + "budget": { + "status": "bounded", + "maxRuntimeMs": 400000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.scheduled-restocks-features", + "checkCount": 3, + "setupRuntimeMs": 61400, + "criterionRuntimeMs": 70214, + "measuredRuntimeMs": 131614, + "budget": { + "status": "bounded", + "maxRuntimeMs": 150000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.server-time-specifications", + "checkCount": 1, + "setupRuntimeMs": 27247, + "criterionRuntimeMs": 112889, + "measuredRuntimeMs": 140136, + "budget": { + "status": "bounded", + "maxRuntimeMs": 300000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.cancellation-accounting-specifications", + "checkCount": 1, + "setupRuntimeMs": 950, + "criterionRuntimeMs": 9512, + "measuredRuntimeMs": 10462, + "budget": { + "status": "bounded", + "maxRuntimeMs": 24000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.catalog-management", + "checkCount": 2, + "setupRuntimeMs": 3361, + "criterionRuntimeMs": 22, + "measuredRuntimeMs": 3383, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.customer-profile", + "checkCount": 1, + "setupRuntimeMs": 554, + "criterionRuntimeMs": 5073, + "measuredRuntimeMs": 5627, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.faceted-search", + "checkCount": 2, + "setupRuntimeMs": 42669, + "criterionRuntimeMs": 25553, + "measuredRuntimeMs": 68222, + "budget": { + "status": "bounded", + "maxRuntimeMs": 141000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.fulfilment-queue", + "checkCount": 2, + "setupRuntimeMs": 1247, + "criterionRuntimeMs": 26641, + "measuredRuntimeMs": 27888, + "budget": { + "status": "bounded", + "maxRuntimeMs": 76000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.inventory-conservation-specifications", + "checkCount": 5, + "setupRuntimeMs": 2502, + "criterionRuntimeMs": 44883, + "measuredRuntimeMs": 47385, + "budget": { + "status": "bounded", + "maxRuntimeMs": 138000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.managed-support", + "checkCount": 1, + "setupRuntimeMs": 1069, + "criterionRuntimeMs": 6073, + "measuredRuntimeMs": 7142, + "budget": { + "status": "bounded", + "maxRuntimeMs": 55000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.notification-preferences", + "checkCount": 1, + "setupRuntimeMs": 739, + "criterionRuntimeMs": 5076, + "measuredRuntimeMs": 5815, + "budget": { + "status": "bounded", + "maxRuntimeMs": 40000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.operations-access-specifications", + "checkCount": 3, + "setupRuntimeMs": 9985, + "criterionRuntimeMs": 34033, + "measuredRuntimeMs": 44018, + "budget": { + "status": "bounded", + "maxRuntimeMs": 98000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.promotion-rules", + "checkCount": 1, + "setupRuntimeMs": 605, + "criterionRuntimeMs": 393, + "measuredRuntimeMs": 998, + "budget": { + "status": "bounded", + "maxRuntimeMs": 45000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.review-access-specifications", + "checkCount": 1, + "setupRuntimeMs": 3958, + "criterionRuntimeMs": 6738, + "measuredRuntimeMs": 10696, + "budget": { + "status": "bounded", + "maxRuntimeMs": 62000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.staff-access", + "checkCount": 1, + "setupRuntimeMs": 0, + "criterionRuntimeMs": 756, + "measuredRuntimeMs": 756, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.staff-roles", + "checkCount": 1, + "setupRuntimeMs": 749, + "criterionRuntimeMs": 27, + "measuredRuntimeMs": 776, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.stock-alerts", + "checkCount": 1, + "setupRuntimeMs": 3908, + "criterionRuntimeMs": 11203, + "measuredRuntimeMs": 15111, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.support-history", + "checkCount": 1, + "setupRuntimeMs": 757, + "criterionRuntimeMs": 1118, + "measuredRuntimeMs": 1875, + "budget": { + "status": "bounded", + "maxRuntimeMs": 50000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.support-intake", + "checkCount": 1, + "setupRuntimeMs": 0, + "criterionRuntimeMs": 415, + "measuredRuntimeMs": 415, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.support-triage", + "checkCount": 3, + "setupRuntimeMs": 872, + "criterionRuntimeMs": 10150, + "measuredRuntimeMs": 11022, + "budget": { + "status": "bounded", + "maxRuntimeMs": 45000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.access-control", + "checkCount": 21, + "setupRuntimeMs": 27215, + "criterionRuntimeMs": 212660, + "measuredRuntimeMs": 239875, + "budget": { + "status": "bounded", + "maxRuntimeMs": 464000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.concurrency-safety", + "checkCount": 6, + "setupRuntimeMs": 24226, + "criterionRuntimeMs": 57991, + "measuredRuntimeMs": 82217, + "budget": { + "status": "bounded", + "maxRuntimeMs": 125000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.external-data-sync", + "checkCount": 3, + "setupRuntimeMs": 596, + "criterionRuntimeMs": 28009, + "measuredRuntimeMs": 28605, + "budget": { + "status": "bounded", + "maxRuntimeMs": 105000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.live-state", + "checkCount": 11, + "setupRuntimeMs": 20181, + "criterionRuntimeMs": 6344, + "measuredRuntimeMs": 26525, + "budget": { + "status": "bounded", + "maxRuntimeMs": 184000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.search-ordering", + "checkCount": 1, + "setupRuntimeMs": 20797, + "criterionRuntimeMs": 5187, + "measuredRuntimeMs": 25984, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.state-durability", + "checkCount": 10, + "setupRuntimeMs": 12061, + "criterionRuntimeMs": 64569, + "measuredRuntimeMs": 76630, + "budget": { + "status": "bounded", + "maxRuntimeMs": 768000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.transactional-integrity", + "checkCount": 6, + "setupRuntimeMs": 23851, + "criterionRuntimeMs": 30721, + "measuredRuntimeMs": 54572, + "budget": { + "status": "bounded", + "maxRuntimeMs": 100000 + }, + "exceeded": false + } + ] + }, + "mutations": { + "caught": 112, + "total": 112 + }, + "baselineDurationMs": 1885802, + "baselineOutput": "ecommerce-l3-add0647be965-postgres-mutation.runs/r1", + "baselineHarnessSha256Before": "d423f94e24aae42fa30fcd169e387eeddf15f50c35cebdb4b461044b98e466f8", + "baselineHarnessSha256After": "d423f94e24aae42fa30fcd169e387eeddf15f50c35cebdb4b461044b98e466f8", + "workers": [ + { + "index": 0, + "runIndex": 0, + "artifact": "ecommerce-l3-add0647be965-postgres-mutation.runs/r1-workers/w1.json", + "mutationIds": [ + "staff-admin-access-survives-role-removal", + "signed-out-purchase-uses-default-account", + "unauthenticated-direct-purchase-uses-default-account", + "cart-update-accepts-negative-quantity", + "cancel-does-not-restore-stock-feature", + "transfer-debits-source-without-crediting-existing-destination", + "progression-customer-sees-staff-tools", + "progression-support-history-is-not-persisted", + "stock-alert-delivery-is-suppressed", + "progression-cancelled-restock-still-runs", + "progression-cancelled-orders-remain-in-revenue", + "progression-staff-can-restock-directly", + "support-history-rows-are-hidden", + "purchase-does-not-broadcast-fulfilment-queue" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-add0647be965-postgres-mutation.runs/r1-workers/w1.stdout.log", + "stderr": "ecommerce-l3-add0647be965-postgres-mutation.runs/r1-workers/w1.stderr.log" + } + }, + { + "index": 1, + "runIndex": 1, + "artifact": "ecommerce-l3-add0647be965-postgres-mutation.runs/r1-workers/w2.json", + "mutationIds": [ + "shipping-counts-sale-twice", + "purchase-stock-change-is-not-broadcast--01-buying", + "direct-purchase-is-attributed-to-previous-account", + "oversell-no-row-lock", + "cancellation-accounting-loses-stock-restoration", + "recommendations-ignore-pending-purchases", + "progression-staff-role-is-lost-on-restart", + "progression-support-history-leaks", + "stock-alert-is-sent-after-every-restock", + "progression-restart-timer-never-runs", + "progression-shipping-keeps-order-pending", + "progression-restock-adds-wrong-quantity", + "authorized-restock-does-not-change-stock", + "admin-state-change-is-not-broadcast" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-add0647be965-postgres-mutation.runs/r1-workers/w2.stdout.log", + "stderr": "ecommerce-l3-add0647be965-postgres-mutation.runs/r1-workers/w2.stderr.log" + } + }, + { + "index": 2, + "runIndex": 2, + "artifact": "ecommerce-l3-add0647be965-postgres-mutation.runs/r1-workers/w3.json", + "mutationIds": [ + "signup-ui-does-not-enter-created-account", + "restock-race-records-wrong-order-total", + "direct-purchase-uses-constant-price", + "purchase-read-write-loses-concurrent-stock", + "cancel-does-not-restore-stock-fresh-client", + "purchases-do-not-affect-best-sellers", + "staff-role-write-precedes-denial", + "progression-managed-support-is-not-shared", + "progression-stock-alerts-leak-across-accounts", + "progression-cart-line-does-not-increment", + "progression-concurrent-cart-line-does-not-increment", + "progression-cart-add-uses-another-account", + "low-stock-threshold-is-two-units", + "admin-sockets-do-not-join-admin-room" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-add0647be965-postgres-mutation.runs/r1-workers/w3.stdout.log", + "stderr": "ecommerce-l3-add0647be965-postgres-mutation.runs/r1-workers/w3.stderr.log" + } + }, + { + "index": 3, + "runIndex": 3, + "artifact": "ecommerce-l3-add0647be965-postgres-mutation.runs/r1-workers/w4.json", + "mutationIds": [ + "duplicate-signup-authenticates-existing-account", + "direct-purchase-order-total-is-offset", + "account-state-reload-discards-session", + "external-stock-polling-disabled", + "cancel-restores-stock-but-keeps-pending-status", + "queue-warehouse-reports-west", + "progression-staff-can-assign-roles", + "progression-managed-support-leaks", + "progression-faceted-filter-ignores-category", + "progression-checkout-leaves-cart-lines", + "progression-concurrent-checkout-leaves-cart-lines", + "progression-customers-can-manage-scheduled-work", + "category-totals-render-as-session-deltas", + "transfer-overdraft-guard-skips-bulk-transfers" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-add0647be965-postgres-mutation.runs/r1-workers/w4.stdout.log", + "stderr": "ecommerce-l3-add0647be965-postgres-mutation.runs/r1-workers/w4.stderr.log" + } + }, + { + "index": 4, + "runIndex": 4, + "artifact": "ecommerce-l3-add0647be965-postgres-mutation.runs/r1-workers/w5.json", + "mutationIds": [ + "password-verification-is-inverted", + "reload-hydrates-an-empty-cart", + "offline-event-clears-account-state", + "server-restart-does-not-resynchronize-catalog", + "operator-authorization-allows-customer-transfer", + "transfer-overwrites-concurrent-purchase-with-stale-stock", + "progression-catalog-product-name-is-not-published", + "progression-promotion-discount-is-offset", + "active-search-uses-purchase-ranking", + "progression-cart-update-uses-wrong-room", + "progression-catalog-ranking-is-reversed", + "progression-restock-does-not-survive-restart", + "profile-summary-ignores-saved-address", + "transfer-does-not-publish-warehouse-totals" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-add0647be965-postgres-mutation.runs/r1-workers/w5.stdout.log", + "stderr": "ecommerce-l3-add0647be965-postgres-mutation.runs/r1-workers/w5.stderr.log" + } + }, + { + "index": 5, + "runIndex": 5, + "artifact": "ecommerce-l3-add0647be965-postgres-mutation.runs/r1-workers/w6.json", + "mutationIds": [ + "correct-signin-is-refused", + "signed-out-visitors-do-not-see-reviews", + "purchase-does-not-decrement-warehouse-stock", + "reconnect-does-not-send-current-catalog", + "customer-can-ship-order-direct-1-1", + "progression-profile-address-is-discarded", + "progression-catalog-variants-are-discarded", + "progression-customer-can-create-promotions", + "progression-pagination-always-shows-first-page", + "progression-order-history-ignores-owner", + "progression-catalog-search-requires-exact-name", + "progression-restock-can-apply-more-than-once", + "support-first-reply-is-hidden", + "progression-support-history-anonymous-leak" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-add0647be965-postgres-mutation.runs/r1-workers/w6.stdout.log", + "stderr": "ecommerce-l3-add0647be965-postgres-mutation.runs/r1-workers/w6.stderr.log" + } + }, + { + "index": 6, + "runIndex": 6, + "artifact": "ecommerce-l3-add0647be965-postgres-mutation.runs/r1-workers/w7.json", + "mutationIds": [ + "reload-discards-session-identity", + "review-average-update-is-not-broadcast", + "review-route-skips-purchase-eligibility", + "open-review-list-ignores-live-update", + "customer-can-cancel-foreign-order-1-1", + "progression-profile-reads-another-account", + "progression-support-intake-is-disabled", + "progression-notification-preferences-do-not-save", + "progression-restock-countdown-is-fixed", + "progression-review-conflict-is-not-updated", + "progression-catalog-price-is-offset", + "restock-overwrites-instead-of-increments", + "notification-sync-flips-saved-toggle", + "checkout-crash-integrity" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-add0647be965-postgres-mutation.runs/r1-workers/w7.stdout.log", + "stderr": "ecommerce-l3-add0647be965-postgres-mutation.runs/r1-workers/w7.stderr.log" + } + }, + { + "index": 7, + "runIndex": 7, + "artifact": "ecommerce-l3-add0647be965-postgres-mutation.runs/r1-workers/w8.json", + "mutationIds": [ + "purchase-does-not-broadcast-ranking", + "admin-warehouse-view-drops-one-location", + "only-shipped-orders-earn-review-eligibility", + "open-review-list-renders-each-review-twice", + "progression-customer-sees-fulfilment-content", + "progression-staff-tools-are-hidden", + "progression-support-triage-update-is-disabled", + "progression-notifications-leak-across-accounts", + "progression-due-restock-does-not-run", + "progression-revenue-double-counts-orders", + "progression-staff-sees-admin-navigation", + "direct-review-access-is-not-checked", + "staff-role-form-reverts-after-save", + "checkout-crash-durability" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-add0647be965-postgres-mutation.runs/r1-workers/w8.stdout.log", + "stderr": "ecommerce-l3-add0647be965-postgres-mutation.runs/r1-workers/w8.stderr.log" + } + } + ] + } + ], + "stable": true, + "sameImage": true, + "sameHarness": true, + "harnessSha256": "d423f94e24aae42fa30fcd169e387eeddf15f50c35cebdb4b461044b98e466f8", + "qualifiedCheckKeys": [ + "ecommerce.feature.accounts.accounts.1a", + "ecommerce.feature.accounts.accounts.1b", + "ecommerce.feature.accounts.accounts.1c", + "ecommerce.feature.accounts.accounts.1d", + "ecommerce.feature.cart-checkout.cart.4a", + "ecommerce.feature.cart-checkout.cart.4d", + "ecommerce.feature.catalog.catalog-ranking.2b", + "ecommerce.feature.catalog.catalog-search.2d", + "ecommerce.feature.catalog.catalog-values.2a", + "ecommerce.feature.purchasing.purchase-order.3c", + "ecommerce.feature.reviews.reviews.6a", + "ecommerce.feature.warehouse-admin.admin-write.103a", + "ecommerce.feature.warehouse-admin.warehouse-view.7b", + "ecommerce.inventory-operations.operational-views.5c", + "ecommerce.inventory-operations.operational-views.5d", + "ecommerce.inventory-operations.operational-views.5e", + "ecommerce.inventory-operations.operational-views.5f", + "ecommerce.inventory-operations.shipping-accounting.202e", + "ecommerce.inventory-operations.stock-conservation.202a", + "ecommerce.inventory-operations.stock-conservation.202b", + "ecommerce.inventory-operations.stock-conservation.202c", + "ecommerce.inventory-operations.stock-conservation.202d", + "ecommerce.inventory-operations.warehouse-transfer.2a", + "ecommerce.l3.deferred-access.scheduled-work-access.317a", + "ecommerce.l3.deferred-durability.restart-survival.311a", + "ecommerce.l3.deferred-integrity.exactly-once.311a", + "ecommerce.l3.scheduled-restocks.scheduled-restocks.302a", + "ecommerce.l3.scheduled-restocks.scheduled-restocks.305a", + "ecommerce.l3.scheduled-restocks.scheduled-restocks.306a", + "ecommerce.l3.server-time.server-time.312a", + "ecommerce.operations-access.fulfilment-queue.1b", + "ecommerce.operations-access.fulfilment-queue.1c", + "ecommerce.operations-access.operator-authorization.201a", + "ecommerce.operations-access.operator-authorization.201c", + "ecommerce.operations-access.order-owner.204a", + "ecommerce.progression.catalog-management.catalog-management.622a", + "ecommerce.progression.catalog-management.catalog-management.622b", + "ecommerce.progression.customer-profile.customer-profile.620c", + "ecommerce.progression.faceted-search.faceted-search.401a", + "ecommerce.progression.faceted-search.faceted-search.402a", + "ecommerce.progression.managed-support.managed-support.613c", + "ecommerce.progression.notification-preferences.notification-preferences.630c", + "ecommerce.progression.promotion-rules.promotion-rule-values.620a", + "ecommerce.progression.review-access-specifications.review-eligibility-direct.618a", + "ecommerce.progression.staff-access.staff-access.601a", + "ecommerce.progression.staff-roles.staff-roles.621c", + "ecommerce.progression.stock-alerts.stock-alert-delivery.631c", + "ecommerce.progression.support-history.support-history.612c", + "ecommerce.progression.support-intake.support-intake.610a", + "ecommerce.progression.support-triage.support-assignment.611a", + "ecommerce.progression.support-triage.support-priority.611b", + "ecommerce.progression.support-triage.support-status.611c", + "ecommerce.returns-pricing.cancellation-and-return.3a", + "ecommerce.returns-pricing.cancellation-and-return.3b", + "ecommerce.returns-pricing.refund-accounting.203a", + "ecommerce.spec.access-control.cart-boundary.109a", + "ecommerce.spec.access-control.cart-boundary.109b", + "ecommerce.spec.access-control.customer-profile-privacy.620b", + "ecommerce.spec.access-control.fulfilment-area-boundary.1d", + "ecommerce.spec.access-control.managed-support-privacy.613b", + "ecommerce.spec.access-control.notification-preferences-privacy.630b", + "ecommerce.spec.access-control.order-ownership.106a", + "ecommerce.spec.access-control.promotion-management-boundary.620b", + "ecommerce.spec.access-control.purchase-attribution.102a", + "ecommerce.spec.access-control.purchase-session.101a", + "ecommerce.spec.access-control.review-eligibility.108a", + "ecommerce.spec.access-control.review-eligibility.108b", + "ecommerce.spec.access-control.signed-out-purchase.3a", + "ecommerce.spec.access-control.staff-area-boundary.601b", + "ecommerce.spec.access-control.staff-role-boundary.621b", + "ecommerce.spec.access-control.staff-role-revocation.621d", + "ecommerce.spec.access-control.stock-alert-privacy.631b", + "ecommerce.spec.access-control.support-history-logout.612d", + "ecommerce.spec.access-control.support-history-privacy.612b", + "ecommerce.spec.access-control.warehouse-area-boundary.7a", + "ecommerce.spec.access-control.warehouse-write-boundary.103b", + "ecommerce.spec.concurrency-safety.duplicate-checkout.203a", + "ecommerce.spec.concurrency-safety.duplicate-checkout.203b", + "ecommerce.spec.concurrency-safety.last-unit.201a", + "ecommerce.spec.concurrency-safety.last-unit.201b", + "ecommerce.spec.concurrency-safety.last-unit.201c", + "ecommerce.spec.concurrency-safety.restock-race.202a", + "ecommerce.spec.external-data-sync.external-stock.901a", + "ecommerce.spec.external-data-sync.external-stock.901c", + "ecommerce.spec.external-data-sync.external-stock.901d", + "ecommerce.spec.live-state.fulfilment-queue.1a", + "ecommerce.spec.live-state.inventory-dashboard.5a", + "ecommerce.spec.live-state.managed-support.613a", + "ecommerce.spec.live-state.open-list.902a", + "ecommerce.spec.live-state.purchase-stock.3b", + "ecommerce.spec.live-state.ranking.2c", + "ecommerce.spec.live-state.rating.6c", + "ecommerce.spec.live-state.sales-dashboard.5b", + "ecommerce.spec.live-state.shared-cart.4c", + "ecommerce.spec.live-state.stock-transfers.2b", + "ecommerce.spec.live-state.warehouse-stock.7c", + "ecommerce.spec.search-ordering.search-ordering.402b", + "ecommerce.spec.state-durability.account-state-recovery.105a", + "ecommerce.spec.state-durability.account-state-recovery.105b", + "ecommerce.spec.state-durability.cart-reload.4b", + "ecommerce.spec.state-durability.checkout-crash-durability.910b", + "ecommerce.spec.state-durability.checkout-crash-integrity.910a", + "ecommerce.spec.state-durability.customer-profile-reload.620a", + "ecommerce.spec.state-durability.notification-preferences-reload.630a", + "ecommerce.spec.state-durability.session-reload.1e", + "ecommerce.spec.state-durability.staff-role-reload.621a", + "ecommerce.spec.state-durability.support-history-reload.612a", + "ecommerce.spec.transactional-integrity.books-balance.107a", + "ecommerce.spec.transactional-integrity.books-balance.107b", + "ecommerce.spec.transactional-integrity.server-price.104a", + "ecommerce.spec.transactional-integrity.stock-alert-deduplication.631a", + "ecommerce.spec.transactional-integrity.stock-transfer-overdraw.2c", + "ecommerce.spec.transactional-integrity.unique-review.6b" + ], + "featureCatalog": { + "contentSha256": "a8c0bf542ec57e0189b99cd3e70a9cea7373c2c83bf4867e11f2c76db329a087", + "id": "ecommerce.questlines" + }, + "diagnostic": false, + "ok": true + } +} diff --git a/tools/stack-bench/qualification-evidence/ecommerce-l3-78ccb6966/postgres-reference.json b/tools/stack-bench/qualification-evidence/ecommerce-l3-78ccb6966/postgres-reference.json new file mode 100644 index 00000000000..7d2909e57d2 --- /dev/null +++ b/tools/stack-bench/qualification-evidence/ecommerce-l3-78ccb6966/postgres-reference.json @@ -0,0 +1,735 @@ +{ + "artifactSchemaVersion": 2, + "kind": "reference_qualification", + "id": "reference-live-postgres-20260917171217-30-reference", + "attempt": { + "id": "reference-live-postgres-20260917171217-30-reference", + "parentId": null + }, + "timestamps": { + "startedAt": "2026-09-17T17:12:17.478Z", + "completedAt": "2026-09-17T17:54:45.076Z" + }, + "identities": { + "engine": { + "id": "stack-bench", + "sha256": "6562a1f38ed757804dc8a6f70ac3c36bb71e7cfd257fbfb4aacd1c30a7412bea" + }, + "recipe": { + "id": "ecommerce.progression-catalog", + "sha256": "add0647be965132c0b9702c5db3ba8265a01b0edc8ca5d820cc152e4ceeb5a89" + }, + "fixture": { + "id": "ecommerce-reference-postgres", + "sha256": "f3906fa01050f00a0ed76c69c256a6b0013bbf72eb72c03aa92d79e47b71c2b8" + }, + "calibration": { + "id": "ecommerce.dependency-l3-calibration", + "sha256": "dc4bf3e29e5d5040becf8fdd846e7d3fd6419a27cb766c8c93a75f19f66c664b" + }, + "experiment": null, + "agentAdapter": null, + "stackAdapter": { + "id": "postgres", + "sha256": null + }, + "packs": [] + }, + "payload": { + "fixture": "ecommerce-reference-postgres", + "fixtureSha256": "f3906fa01050f00a0ed76c69c256a6b0013bbf72eb72c03aa92d79e47b71c2b8", + "requiredRepetitions": 1, + "isolation": "docker", + "runner": { + "schemaVersion": 1, + "mode": "appliance", + "platform": "linux", + "architecture": "x64", + "hostname": "docker-desktop", + "dockerEngineVersion": "29.6.2", + "dockerOs": "linux", + "dockerArchitecture": "x86_64", + "kernelVersion": "6.6.87.2-microsoft-standard-WSL2", + "cpuCount": 32, + "memoryBytes": 49232842752, + "containersRunning": 11, + "packageRegistry": "http://127.0.0.1:4873/" + }, + "qualificationScope": { + "checksSha256": "64d4f2af43f951e8c70d61ed1e64baf5f376ce3fa6031b1a9d79db2bd48aeaff", + "executableSha256": "233641c255d195b18bf3717b2e2fbae69a153425806d7fb53709b97d1994eb8d", + "kind": "reference", + "mutationSha256": null, + "recipe": { + "contentSha256": "add0647be965132c0b9702c5db3ba8265a01b0edc8ca5d820cc152e4ceeb5a89", + "id": "ecommerce.progression-catalog" + }, + "schemaVersion": 3, + "stack": { + "id": "postgres", + "reference": { + "id": "ecommerce-reference-postgres", + "sourceSha256": "f3906fa01050f00a0ed76c69c256a6b0013bbf72eb72c03aa92d79e47b71c2b8" + }, + "version": "1.6.0" + }, + "sha256": "3e53c28d95a4081dbddfc375ea8a96f0107f5d2a09166ebebf44704d9c14f868" + }, + "mutationControl": false, + "runs": [ + { + "repetition": 1, + "output": "ecommerce-l3-add0647be965-postgres-mutation.runs/r1", + "durationMs": 1885802, + "processError": null, + "harnessSha256Before": "d423f94e24aae42fa30fcd169e387eeddf15f50c35cebdb4b461044b98e466f8", + "harnessSha256After": "d423f94e24aae42fa30fcd169e387eeddf15f50c35cebdb4b461044b98e466f8", + "ok": true, + "failures": [], + "runId": "ecommerce-postgres-run0-20260917171218-1079321b", + "score": "182/182", + "imageId": "sha256:32ff9a9e519ba9d1af2fe72f24622caa8ca7a9f2baf2338c6b1e0435e6ac5455", + "criteria": 113, + "zeroPointCriteria": 0, + "fingerprint": "0d6c57cc6ec1dd08dd5409aa619f28d1aa7c74e27644a80dd2312a0038b978cc", + "outcome": "passed", + "packRuntime": { + "schemaVersion": 1, + "metric": "pack-check-wall-clock-sum-v1", + "packs": [ + { + "id": "ecommerce.feature.accounts", + "checkCount": 4, + "setupRuntimeMs": 1045, + "criterionRuntimeMs": 15156, + "measuredRuntimeMs": 16201, + "budget": { + "status": "bounded", + "maxRuntimeMs": 18000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.cart", + "checkCount": 1, + "setupRuntimeMs": 458, + "criterionRuntimeMs": 6081, + "measuredRuntimeMs": 6539, + "budget": { + "status": "bounded", + "maxRuntimeMs": 42000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.catalog-discovery", + "checkCount": 2, + "setupRuntimeMs": 0, + "criterionRuntimeMs": 1855, + "measuredRuntimeMs": 1855, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.catalog-items", + "checkCount": 1, + "setupRuntimeMs": 0, + "criterionRuntimeMs": 229, + "measuredRuntimeMs": 229, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.checkout", + "checkCount": 1, + "setupRuntimeMs": 458, + "criterionRuntimeMs": 5987, + "measuredRuntimeMs": 6445, + "budget": { + "status": "bounded", + "maxRuntimeMs": 42000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.purchasing", + "checkCount": 1, + "setupRuntimeMs": 336, + "criterionRuntimeMs": 1164, + "measuredRuntimeMs": 1500, + "budget": { + "status": "bounded", + "maxRuntimeMs": 24000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.reviews", + "checkCount": 1, + "setupRuntimeMs": 1742, + "criterionRuntimeMs": 363, + "measuredRuntimeMs": 2105, + "budget": { + "status": "bounded", + "maxRuntimeMs": 22000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.warehouse-admin", + "checkCount": 2, + "setupRuntimeMs": 1311, + "criterionRuntimeMs": 4333, + "measuredRuntimeMs": 5644, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.inventory-dashboard", + "checkCount": 1, + "setupRuntimeMs": 3442, + "criterionRuntimeMs": 8, + "measuredRuntimeMs": 3450, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.order-cancellation-features", + "checkCount": 2, + "setupRuntimeMs": 1001, + "criterionRuntimeMs": 11189, + "measuredRuntimeMs": 12190, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.recommendations", + "checkCount": 1, + "setupRuntimeMs": 344, + "criterionRuntimeMs": 5223, + "measuredRuntimeMs": 5567, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.sales-dashboard", + "checkCount": 2, + "setupRuntimeMs": 2047, + "criterionRuntimeMs": 4988, + "measuredRuntimeMs": 7035, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.stock-transfers-features", + "checkCount": 1, + "setupRuntimeMs": 414, + "criterionRuntimeMs": 971, + "measuredRuntimeMs": 1385, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.deferred-access-specifications", + "checkCount": 1, + "setupRuntimeMs": 20950, + "criterionRuntimeMs": 4260, + "measuredRuntimeMs": 25210, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.deferred-durability-specifications", + "checkCount": 1, + "setupRuntimeMs": 126312, + "criterionRuntimeMs": 38980, + "measuredRuntimeMs": 165292, + "budget": { + "status": "bounded", + "maxRuntimeMs": 720000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.deferred-integrity-specifications", + "checkCount": 1, + "setupRuntimeMs": 42271, + "criterionRuntimeMs": 38576, + "measuredRuntimeMs": 80847, + "budget": { + "status": "bounded", + "maxRuntimeMs": 400000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.scheduled-restocks-features", + "checkCount": 3, + "setupRuntimeMs": 61400, + "criterionRuntimeMs": 70214, + "measuredRuntimeMs": 131614, + "budget": { + "status": "bounded", + "maxRuntimeMs": 150000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.server-time-specifications", + "checkCount": 1, + "setupRuntimeMs": 27247, + "criterionRuntimeMs": 112889, + "measuredRuntimeMs": 140136, + "budget": { + "status": "bounded", + "maxRuntimeMs": 300000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.cancellation-accounting-specifications", + "checkCount": 1, + "setupRuntimeMs": 950, + "criterionRuntimeMs": 9512, + "measuredRuntimeMs": 10462, + "budget": { + "status": "bounded", + "maxRuntimeMs": 24000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.catalog-management", + "checkCount": 2, + "setupRuntimeMs": 3361, + "criterionRuntimeMs": 22, + "measuredRuntimeMs": 3383, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.customer-profile", + "checkCount": 1, + "setupRuntimeMs": 554, + "criterionRuntimeMs": 5073, + "measuredRuntimeMs": 5627, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.faceted-search", + "checkCount": 2, + "setupRuntimeMs": 42669, + "criterionRuntimeMs": 25553, + "measuredRuntimeMs": 68222, + "budget": { + "status": "bounded", + "maxRuntimeMs": 141000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.fulfilment-queue", + "checkCount": 2, + "setupRuntimeMs": 1247, + "criterionRuntimeMs": 26641, + "measuredRuntimeMs": 27888, + "budget": { + "status": "bounded", + "maxRuntimeMs": 76000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.inventory-conservation-specifications", + "checkCount": 5, + "setupRuntimeMs": 2502, + "criterionRuntimeMs": 44883, + "measuredRuntimeMs": 47385, + "budget": { + "status": "bounded", + "maxRuntimeMs": 138000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.managed-support", + "checkCount": 1, + "setupRuntimeMs": 1069, + "criterionRuntimeMs": 6073, + "measuredRuntimeMs": 7142, + "budget": { + "status": "bounded", + "maxRuntimeMs": 55000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.notification-preferences", + "checkCount": 1, + "setupRuntimeMs": 739, + "criterionRuntimeMs": 5076, + "measuredRuntimeMs": 5815, + "budget": { + "status": "bounded", + "maxRuntimeMs": 40000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.operations-access-specifications", + "checkCount": 3, + "setupRuntimeMs": 9985, + "criterionRuntimeMs": 34033, + "measuredRuntimeMs": 44018, + "budget": { + "status": "bounded", + "maxRuntimeMs": 98000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.promotion-rules", + "checkCount": 1, + "setupRuntimeMs": 605, + "criterionRuntimeMs": 393, + "measuredRuntimeMs": 998, + "budget": { + "status": "bounded", + "maxRuntimeMs": 45000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.review-access-specifications", + "checkCount": 1, + "setupRuntimeMs": 3958, + "criterionRuntimeMs": 6738, + "measuredRuntimeMs": 10696, + "budget": { + "status": "bounded", + "maxRuntimeMs": 62000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.staff-access", + "checkCount": 1, + "setupRuntimeMs": 0, + "criterionRuntimeMs": 756, + "measuredRuntimeMs": 756, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.staff-roles", + "checkCount": 1, + "setupRuntimeMs": 749, + "criterionRuntimeMs": 27, + "measuredRuntimeMs": 776, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.stock-alerts", + "checkCount": 1, + "setupRuntimeMs": 3908, + "criterionRuntimeMs": 11203, + "measuredRuntimeMs": 15111, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.support-history", + "checkCount": 1, + "setupRuntimeMs": 757, + "criterionRuntimeMs": 1118, + "measuredRuntimeMs": 1875, + "budget": { + "status": "bounded", + "maxRuntimeMs": 50000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.support-intake", + "checkCount": 1, + "setupRuntimeMs": 0, + "criterionRuntimeMs": 415, + "measuredRuntimeMs": 415, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.support-triage", + "checkCount": 3, + "setupRuntimeMs": 872, + "criterionRuntimeMs": 10150, + "measuredRuntimeMs": 11022, + "budget": { + "status": "bounded", + "maxRuntimeMs": 45000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.access-control", + "checkCount": 21, + "setupRuntimeMs": 27215, + "criterionRuntimeMs": 212660, + "measuredRuntimeMs": 239875, + "budget": { + "status": "bounded", + "maxRuntimeMs": 464000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.concurrency-safety", + "checkCount": 6, + "setupRuntimeMs": 24226, + "criterionRuntimeMs": 57991, + "measuredRuntimeMs": 82217, + "budget": { + "status": "bounded", + "maxRuntimeMs": 125000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.external-data-sync", + "checkCount": 3, + "setupRuntimeMs": 596, + "criterionRuntimeMs": 28009, + "measuredRuntimeMs": 28605, + "budget": { + "status": "bounded", + "maxRuntimeMs": 105000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.live-state", + "checkCount": 11, + "setupRuntimeMs": 20181, + "criterionRuntimeMs": 6344, + "measuredRuntimeMs": 26525, + "budget": { + "status": "bounded", + "maxRuntimeMs": 184000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.search-ordering", + "checkCount": 1, + "setupRuntimeMs": 20797, + "criterionRuntimeMs": 5187, + "measuredRuntimeMs": 25984, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.state-durability", + "checkCount": 10, + "setupRuntimeMs": 12061, + "criterionRuntimeMs": 64569, + "measuredRuntimeMs": 76630, + "budget": { + "status": "bounded", + "maxRuntimeMs": 768000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.transactional-integrity", + "checkCount": 6, + "setupRuntimeMs": 23851, + "criterionRuntimeMs": 30721, + "measuredRuntimeMs": 54572, + "budget": { + "status": "bounded", + "maxRuntimeMs": 100000 + }, + "exceeded": false + } + ] + }, + "mutations": null + } + ], + "stable": true, + "sameImage": true, + "sameHarness": true, + "harnessSha256": "d423f94e24aae42fa30fcd169e387eeddf15f50c35cebdb4b461044b98e466f8", + "qualifiedCheckKeys": [ + "ecommerce.feature.accounts.accounts.1a", + "ecommerce.feature.accounts.accounts.1b", + "ecommerce.feature.accounts.accounts.1c", + "ecommerce.feature.accounts.accounts.1d", + "ecommerce.feature.cart-checkout.cart.4a", + "ecommerce.feature.cart-checkout.cart.4d", + "ecommerce.feature.catalog.catalog-ranking.2b", + "ecommerce.feature.catalog.catalog-search.2d", + "ecommerce.feature.catalog.catalog-values.2a", + "ecommerce.feature.purchasing.purchase-order.3c", + "ecommerce.feature.reviews.reviews.6a", + "ecommerce.feature.warehouse-admin.admin-write.103a", + "ecommerce.feature.warehouse-admin.warehouse-view.7b", + "ecommerce.inventory-operations.operational-views.5c", + "ecommerce.inventory-operations.operational-views.5d", + "ecommerce.inventory-operations.operational-views.5e", + "ecommerce.inventory-operations.operational-views.5f", + "ecommerce.inventory-operations.shipping-accounting.202e", + "ecommerce.inventory-operations.stock-conservation.202a", + "ecommerce.inventory-operations.stock-conservation.202b", + "ecommerce.inventory-operations.stock-conservation.202c", + "ecommerce.inventory-operations.stock-conservation.202d", + "ecommerce.inventory-operations.warehouse-transfer.2a", + "ecommerce.l3.deferred-access.scheduled-work-access.317a", + "ecommerce.l3.deferred-durability.restart-survival.311a", + "ecommerce.l3.deferred-integrity.exactly-once.311a", + "ecommerce.l3.scheduled-restocks.scheduled-restocks.302a", + "ecommerce.l3.scheduled-restocks.scheduled-restocks.305a", + "ecommerce.l3.scheduled-restocks.scheduled-restocks.306a", + "ecommerce.l3.server-time.server-time.312a", + "ecommerce.operations-access.fulfilment-queue.1b", + "ecommerce.operations-access.fulfilment-queue.1c", + "ecommerce.operations-access.operator-authorization.201a", + "ecommerce.operations-access.operator-authorization.201c", + "ecommerce.operations-access.order-owner.204a", + "ecommerce.progression.catalog-management.catalog-management.622a", + "ecommerce.progression.catalog-management.catalog-management.622b", + "ecommerce.progression.customer-profile.customer-profile.620c", + "ecommerce.progression.faceted-search.faceted-search.401a", + "ecommerce.progression.faceted-search.faceted-search.402a", + "ecommerce.progression.managed-support.managed-support.613c", + "ecommerce.progression.notification-preferences.notification-preferences.630c", + "ecommerce.progression.promotion-rules.promotion-rule-values.620a", + "ecommerce.progression.review-access-specifications.review-eligibility-direct.618a", + "ecommerce.progression.staff-access.staff-access.601a", + "ecommerce.progression.staff-roles.staff-roles.621c", + "ecommerce.progression.stock-alerts.stock-alert-delivery.631c", + "ecommerce.progression.support-history.support-history.612c", + "ecommerce.progression.support-intake.support-intake.610a", + "ecommerce.progression.support-triage.support-assignment.611a", + "ecommerce.progression.support-triage.support-priority.611b", + "ecommerce.progression.support-triage.support-status.611c", + "ecommerce.returns-pricing.cancellation-and-return.3a", + "ecommerce.returns-pricing.cancellation-and-return.3b", + "ecommerce.returns-pricing.refund-accounting.203a", + "ecommerce.spec.access-control.cart-boundary.109a", + "ecommerce.spec.access-control.cart-boundary.109b", + "ecommerce.spec.access-control.customer-profile-privacy.620b", + "ecommerce.spec.access-control.fulfilment-area-boundary.1d", + "ecommerce.spec.access-control.managed-support-privacy.613b", + "ecommerce.spec.access-control.notification-preferences-privacy.630b", + "ecommerce.spec.access-control.order-ownership.106a", + "ecommerce.spec.access-control.promotion-management-boundary.620b", + "ecommerce.spec.access-control.purchase-attribution.102a", + "ecommerce.spec.access-control.purchase-session.101a", + "ecommerce.spec.access-control.review-eligibility.108a", + "ecommerce.spec.access-control.review-eligibility.108b", + "ecommerce.spec.access-control.signed-out-purchase.3a", + "ecommerce.spec.access-control.staff-area-boundary.601b", + "ecommerce.spec.access-control.staff-role-boundary.621b", + "ecommerce.spec.access-control.staff-role-revocation.621d", + "ecommerce.spec.access-control.stock-alert-privacy.631b", + "ecommerce.spec.access-control.support-history-logout.612d", + "ecommerce.spec.access-control.support-history-privacy.612b", + "ecommerce.spec.access-control.warehouse-area-boundary.7a", + "ecommerce.spec.access-control.warehouse-write-boundary.103b", + "ecommerce.spec.concurrency-safety.duplicate-checkout.203a", + "ecommerce.spec.concurrency-safety.duplicate-checkout.203b", + "ecommerce.spec.concurrency-safety.last-unit.201a", + "ecommerce.spec.concurrency-safety.last-unit.201b", + "ecommerce.spec.concurrency-safety.last-unit.201c", + "ecommerce.spec.concurrency-safety.restock-race.202a", + "ecommerce.spec.external-data-sync.external-stock.901a", + "ecommerce.spec.external-data-sync.external-stock.901c", + "ecommerce.spec.external-data-sync.external-stock.901d", + "ecommerce.spec.live-state.fulfilment-queue.1a", + "ecommerce.spec.live-state.inventory-dashboard.5a", + "ecommerce.spec.live-state.managed-support.613a", + "ecommerce.spec.live-state.open-list.902a", + "ecommerce.spec.live-state.purchase-stock.3b", + "ecommerce.spec.live-state.ranking.2c", + "ecommerce.spec.live-state.rating.6c", + "ecommerce.spec.live-state.sales-dashboard.5b", + "ecommerce.spec.live-state.shared-cart.4c", + "ecommerce.spec.live-state.stock-transfers.2b", + "ecommerce.spec.live-state.warehouse-stock.7c", + "ecommerce.spec.search-ordering.search-ordering.402b", + "ecommerce.spec.state-durability.account-state-recovery.105a", + "ecommerce.spec.state-durability.account-state-recovery.105b", + "ecommerce.spec.state-durability.cart-reload.4b", + "ecommerce.spec.state-durability.checkout-crash-durability.910b", + "ecommerce.spec.state-durability.checkout-crash-integrity.910a", + "ecommerce.spec.state-durability.customer-profile-reload.620a", + "ecommerce.spec.state-durability.notification-preferences-reload.630a", + "ecommerce.spec.state-durability.session-reload.1e", + "ecommerce.spec.state-durability.staff-role-reload.621a", + "ecommerce.spec.state-durability.support-history-reload.612a", + "ecommerce.spec.transactional-integrity.books-balance.107a", + "ecommerce.spec.transactional-integrity.books-balance.107b", + "ecommerce.spec.transactional-integrity.server-price.104a", + "ecommerce.spec.transactional-integrity.stock-alert-deduplication.631a", + "ecommerce.spec.transactional-integrity.stock-transfer-overdraw.2c", + "ecommerce.spec.transactional-integrity.unique-review.6b" + ], + "featureCatalog": { + "contentSha256": "a8c0bf542ec57e0189b99cd3e70a9cea7373c2c83bf4867e11f2c76db329a087", + "id": "ecommerce.questlines" + }, + "diagnostic": false, + "ok": true + } +} diff --git a/tools/stack-bench/qualification-evidence/ecommerce-l3-78ccb6966/spacetime-mutation.json b/tools/stack-bench/qualification-evidence/ecommerce-l3-78ccb6966/spacetime-mutation.json new file mode 100644 index 00000000000..618e19e5b71 --- /dev/null +++ b/tools/stack-bench/qualification-evidence/ecommerce-l3-78ccb6966/spacetime-mutation.json @@ -0,0 +1,957 @@ +{ + "artifactSchemaVersion": 2, + "kind": "reference_qualification", + "id": "reference-live-spacetime-20260917171218-30", + "attempt": { + "id": "reference-live-spacetime-20260917171218-30", + "parentId": null + }, + "timestamps": { + "startedAt": "2026-09-17T17:12:18.472Z", + "completedAt": "2026-09-17T18:05:40.088Z" + }, + "identities": { + "engine": { + "id": "stack-bench", + "sha256": "6562a1f38ed757804dc8a6f70ac3c36bb71e7cfd257fbfb4aacd1c30a7412bea" + }, + "recipe": { + "id": "ecommerce.progression-catalog", + "sha256": "add0647be965132c0b9702c5db3ba8265a01b0edc8ca5d820cc152e4ceeb5a89" + }, + "fixture": { + "id": "ecommerce-reference-spacetime", + "sha256": "7ba1f548e89f461b95b5caf843b0fbcf2b81278428d02869d7f47e1a199eaf6e" + }, + "calibration": { + "id": "ecommerce.dependency-l3-calibration", + "sha256": "dc4bf3e29e5d5040becf8fdd846e7d3fd6419a27cb766c8c93a75f19f66c664b" + }, + "experiment": null, + "agentAdapter": null, + "stackAdapter": { + "id": "spacetime", + "sha256": null + }, + "packs": [] + }, + "payload": { + "fixture": "ecommerce-reference-spacetime", + "fixtureSha256": "7ba1f548e89f461b95b5caf843b0fbcf2b81278428d02869d7f47e1a199eaf6e", + "requiredRepetitions": 1, + "isolation": "docker", + "runner": { + "schemaVersion": 1, + "mode": "appliance", + "platform": "linux", + "architecture": "x64", + "hostname": "docker-desktop", + "dockerEngineVersion": "29.6.2", + "dockerOs": "linux", + "dockerArchitecture": "x86_64", + "kernelVersion": "6.6.87.2-microsoft-standard-WSL2", + "cpuCount": 32, + "memoryBytes": 49232842752, + "containersRunning": 13, + "packageRegistry": "http://127.0.0.1:4873/" + }, + "qualificationScope": { + "checksSha256": "64d4f2af43f951e8c70d61ed1e64baf5f376ce3fa6031b1a9d79db2bd48aeaff", + "executableSha256": "56429eab8bd9ba42bcc31e94d2c598364abda6aa1b909fb60fc1a54a61a64530", + "kind": "mutation", + "mutationSha256": "76e4a27d587101751a0444fdbcd0223f88a3c738bf44d17f7c0f1b79b2134944", + "recipe": { + "contentSha256": "add0647be965132c0b9702c5db3ba8265a01b0edc8ca5d820cc152e4ceeb5a89", + "id": "ecommerce.progression-catalog" + }, + "schemaVersion": 3, + "stack": { + "id": "spacetime", + "reference": { + "id": "ecommerce-reference-spacetime", + "sourceSha256": "7ba1f548e89f461b95b5caf843b0fbcf2b81278428d02869d7f47e1a199eaf6e" + }, + "version": "1.4.0" + }, + "sha256": "1c09a9ee754123dde12e1813e7feb73c0be8f979a651106d46fa20a36181ff39" + }, + "mutationControl": true, + "runs": [ + { + "repetition": 1, + "output": "ecommerce-l3-add0647be965-spacetime-mutation.runs/r1-workers", + "durationMs": 3201546, + "processError": null, + "harnessSha256Before": "d423f94e24aae42fa30fcd169e387eeddf15f50c35cebdb4b461044b98e466f8", + "harnessSha256After": "d423f94e24aae42fa30fcd169e387eeddf15f50c35cebdb4b461044b98e466f8", + "ok": true, + "failures": [], + "runId": "reference-live-spacetime-20260917171218-30", + "score": "182/182", + "imageId": "sha256:32ff9a9e519ba9d1af2fe72f24622caa8ca7a9f2baf2338c6b1e0435e6ac5455", + "criteria": 113, + "zeroPointCriteria": 0, + "fingerprint": "0d6c57cc6ec1dd08dd5409aa619f28d1aa7c74e27644a80dd2312a0038b978cc", + "outcome": "passed", + "packRuntime": { + "schemaVersion": 1, + "metric": "pack-check-wall-clock-sum-v1", + "packs": [ + { + "id": "ecommerce.feature.accounts", + "checkCount": 4, + "setupRuntimeMs": 894, + "criterionRuntimeMs": 15047, + "measuredRuntimeMs": 15941, + "budget": { + "status": "bounded", + "maxRuntimeMs": 18000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.cart", + "checkCount": 1, + "setupRuntimeMs": 410, + "criterionRuntimeMs": 6040, + "measuredRuntimeMs": 6450, + "budget": { + "status": "bounded", + "maxRuntimeMs": 42000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.catalog-discovery", + "checkCount": 2, + "setupRuntimeMs": 1, + "criterionRuntimeMs": 2239, + "measuredRuntimeMs": 2240, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.catalog-items", + "checkCount": 1, + "setupRuntimeMs": 0, + "criterionRuntimeMs": 260, + "measuredRuntimeMs": 260, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.checkout", + "checkCount": 1, + "setupRuntimeMs": 410, + "criterionRuntimeMs": 6258, + "measuredRuntimeMs": 6668, + "budget": { + "status": "bounded", + "maxRuntimeMs": 42000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.purchasing", + "checkCount": 1, + "setupRuntimeMs": 401, + "criterionRuntimeMs": 1184, + "measuredRuntimeMs": 1585, + "budget": { + "status": "bounded", + "maxRuntimeMs": 24000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.reviews", + "checkCount": 1, + "setupRuntimeMs": 1679, + "criterionRuntimeMs": 351, + "measuredRuntimeMs": 2030, + "budget": { + "status": "bounded", + "maxRuntimeMs": 22000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.warehouse-admin", + "checkCount": 2, + "setupRuntimeMs": 1222, + "criterionRuntimeMs": 4632, + "measuredRuntimeMs": 5854, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.inventory-dashboard", + "checkCount": 1, + "setupRuntimeMs": 5352, + "criterionRuntimeMs": 8, + "measuredRuntimeMs": 5360, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.order-cancellation-features", + "checkCount": 2, + "setupRuntimeMs": 746, + "criterionRuntimeMs": 12119, + "measuredRuntimeMs": 12865, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.recommendations", + "checkCount": 1, + "setupRuntimeMs": 313, + "criterionRuntimeMs": 5141, + "measuredRuntimeMs": 5454, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.sales-dashboard", + "checkCount": 2, + "setupRuntimeMs": 1915, + "criterionRuntimeMs": 5754, + "measuredRuntimeMs": 7669, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.stock-transfers-features", + "checkCount": 1, + "setupRuntimeMs": 352, + "criterionRuntimeMs": 1834, + "measuredRuntimeMs": 2186, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.deferred-access-specifications", + "checkCount": 1, + "setupRuntimeMs": 20776, + "criterionRuntimeMs": 4248, + "measuredRuntimeMs": 25024, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.deferred-durability-specifications", + "checkCount": 1, + "setupRuntimeMs": 124952, + "criterionRuntimeMs": 42098, + "measuredRuntimeMs": 167050, + "budget": { + "status": "bounded", + "maxRuntimeMs": 720000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.deferred-integrity-specifications", + "checkCount": 1, + "setupRuntimeMs": 40477, + "criterionRuntimeMs": 37125, + "measuredRuntimeMs": 77602, + "budget": { + "status": "bounded", + "maxRuntimeMs": 400000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.scheduled-restocks-features", + "checkCount": 3, + "setupRuntimeMs": 61395, + "criterionRuntimeMs": 70364, + "measuredRuntimeMs": 131759, + "budget": { + "status": "bounded", + "maxRuntimeMs": 150000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.server-time-specifications", + "checkCount": 1, + "setupRuntimeMs": 25897, + "criterionRuntimeMs": 115051, + "measuredRuntimeMs": 140948, + "budget": { + "status": "bounded", + "maxRuntimeMs": 300000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.cancellation-accounting-specifications", + "checkCount": 1, + "setupRuntimeMs": 662, + "criterionRuntimeMs": 12161, + "measuredRuntimeMs": 12823, + "budget": { + "status": "bounded", + "maxRuntimeMs": 24000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.catalog-management", + "checkCount": 2, + "setupRuntimeMs": 3623, + "criterionRuntimeMs": 23, + "measuredRuntimeMs": 3646, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.customer-profile", + "checkCount": 1, + "setupRuntimeMs": 463, + "criterionRuntimeMs": 5074, + "measuredRuntimeMs": 5537, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.faceted-search", + "checkCount": 2, + "setupRuntimeMs": 44379, + "criterionRuntimeMs": 25588, + "measuredRuntimeMs": 69967, + "budget": { + "status": "bounded", + "maxRuntimeMs": 141000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.fulfilment-queue", + "checkCount": 2, + "setupRuntimeMs": 1010, + "criterionRuntimeMs": 28622, + "measuredRuntimeMs": 29632, + "budget": { + "status": "bounded", + "maxRuntimeMs": 76000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.inventory-conservation-specifications", + "checkCount": 5, + "setupRuntimeMs": 2159, + "criterionRuntimeMs": 55507, + "measuredRuntimeMs": 57666, + "budget": { + "status": "bounded", + "maxRuntimeMs": 138000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.managed-support", + "checkCount": 1, + "setupRuntimeMs": 850, + "criterionRuntimeMs": 6845, + "measuredRuntimeMs": 7695, + "budget": { + "status": "bounded", + "maxRuntimeMs": 55000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.notification-preferences", + "checkCount": 1, + "setupRuntimeMs": 612, + "criterionRuntimeMs": 5075, + "measuredRuntimeMs": 5687, + "budget": { + "status": "bounded", + "maxRuntimeMs": 40000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.operations-access-specifications", + "checkCount": 3, + "setupRuntimeMs": 9554, + "criterionRuntimeMs": 38253, + "measuredRuntimeMs": 47807, + "budget": { + "status": "bounded", + "maxRuntimeMs": 98000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.promotion-rules", + "checkCount": 1, + "setupRuntimeMs": 581, + "criterionRuntimeMs": 369, + "measuredRuntimeMs": 950, + "budget": { + "status": "bounded", + "maxRuntimeMs": 45000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.review-access-specifications", + "checkCount": 1, + "setupRuntimeMs": 3893, + "criterionRuntimeMs": 7169, + "measuredRuntimeMs": 11062, + "budget": { + "status": "bounded", + "maxRuntimeMs": 62000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.staff-access", + "checkCount": 1, + "setupRuntimeMs": 0, + "criterionRuntimeMs": 645, + "measuredRuntimeMs": 645, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.staff-roles", + "checkCount": 1, + "setupRuntimeMs": 486, + "criterionRuntimeMs": 30, + "measuredRuntimeMs": 516, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.stock-alerts", + "checkCount": 1, + "setupRuntimeMs": 5786, + "criterionRuntimeMs": 12418, + "measuredRuntimeMs": 18204, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.support-history", + "checkCount": 1, + "setupRuntimeMs": 743, + "criterionRuntimeMs": 1425, + "measuredRuntimeMs": 2168, + "budget": { + "status": "bounded", + "maxRuntimeMs": 50000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.support-intake", + "checkCount": 1, + "setupRuntimeMs": 0, + "criterionRuntimeMs": 442, + "measuredRuntimeMs": 442, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.support-triage", + "checkCount": 3, + "setupRuntimeMs": 705, + "criterionRuntimeMs": 10806, + "measuredRuntimeMs": 11511, + "budget": { + "status": "bounded", + "maxRuntimeMs": 45000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.access-control", + "checkCount": 21, + "setupRuntimeMs": 28144, + "criterionRuntimeMs": 224590, + "measuredRuntimeMs": 252734, + "budget": { + "status": "bounded", + "maxRuntimeMs": 464000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.concurrency-safety", + "checkCount": 6, + "setupRuntimeMs": 28113, + "criterionRuntimeMs": 64430, + "measuredRuntimeMs": 92543, + "budget": { + "status": "bounded", + "maxRuntimeMs": 125000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.external-data-sync", + "checkCount": 3, + "setupRuntimeMs": 611, + "criterionRuntimeMs": 33083, + "measuredRuntimeMs": 33694, + "budget": { + "status": "bounded", + "maxRuntimeMs": 105000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.live-state", + "checkCount": 11, + "setupRuntimeMs": 20587, + "criterionRuntimeMs": 7328, + "measuredRuntimeMs": 27915, + "budget": { + "status": "bounded", + "maxRuntimeMs": 184000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.search-ordering", + "checkCount": 1, + "setupRuntimeMs": 21514, + "criterionRuntimeMs": 5226, + "measuredRuntimeMs": 26740, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.state-durability", + "checkCount": 10, + "setupRuntimeMs": 8929, + "criterionRuntimeMs": 57873, + "measuredRuntimeMs": 66802, + "budget": { + "status": "bounded", + "maxRuntimeMs": 768000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.transactional-integrity", + "checkCount": 6, + "setupRuntimeMs": 25270, + "criterionRuntimeMs": 35966, + "measuredRuntimeMs": 61236, + "budget": { + "status": "bounded", + "maxRuntimeMs": 100000 + }, + "exceeded": false + } + ] + }, + "mutations": { + "caught": 117, + "total": 117 + }, + "baselineDurationMs": 2304660, + "baselineOutput": "ecommerce-l3-add0647be965-spacetime-mutation.runs/r1", + "baselineHarnessSha256Before": "d423f94e24aae42fa30fcd169e387eeddf15f50c35cebdb4b461044b98e466f8", + "baselineHarnessSha256After": "d423f94e24aae42fa30fcd169e387eeddf15f50c35cebdb4b461044b98e466f8", + "workers": [ + { + "index": 0, + "runIndex": 0, + "artifact": "ecommerce-l3-add0647be965-spacetime-mutation.runs/r1-workers/w1.json", + "mutationIds": [ + "staff-admin-access-survives-role-removal", + "catalog-seeds-the-wrong-air-purifier-price", + "existing-cart-line-does-not-increment-basic-cart", + "warehouse-view-omits-west", + "admin-revenue-double-counts-every-order", + "stock-subscription-snapshotted-once", + "cancel-restores-stock-but-keeps-pending-status", + "operator-authorization-allows-customer-shipping", + "customers-can-schedule-restocks", + "catalog-variants-are-discarded", + "managed-support-live-replies-stay-at-initial-snapshot", + "staff-can-assign-roles", + "support-priority-is-discarded", + "category-totals-count-only-since-the-dashboard-opened", + "warehouse-totals-are-frozen-at-page-load" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-add0647be965-spacetime-mutation.runs/r1-workers/w1.stdout.log", + "stderr": "ecommerce-l3-add0647be965-spacetime-mutation.runs/r1-workers/w1.stderr.log" + } + }, + { + "index": 1, + "runIndex": 1, + "artifact": "ecommerce-l3-add0647be965-spacetime-mutation.runs/r1-workers/w2.json", + "mutationIds": [ + "shipping-counts-sale-twice", + "catalog-tie-breaks-in-reverse-alphabetical-order--01-catalog-ranking", + "cart-is-deleted-when-owner-disconnects", + "guest-purchase-falls-back-to-the-admin-account", + "purchases-do-not-leave-the-warehouses", + "stock-view-ignores-update-across-app-server-stop", + "cancelled-order-remains-in-revenue-feature", + "transfer-debits-source-without-crediting-existing-destination", + "scheduled-restock-execution-queue-is-process-local", + "profile-is-lost-on-fresh-account-login", + "notification-preferences-are-not-saved", + "stock-alert-delivery-is-suppressed", + "support-status-is-discarded", + "profile-summary-ignores-a-profile-saved-this-session", + "transfer-skips-the-source-holding-check" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-add0647be965-spacetime-mutation.runs/r1-workers/w2.stdout.log", + "stderr": "ecommerce-l3-add0647be965-spacetime-mutation.runs/r1-workers/w2.stderr.log" + } + }, + { + "index": 2, + "runIndex": 2, + "artifact": "ecommerce-l3-add0647be965-spacetime-mutation.runs/r1-workers/w3.json", + "mutationIds": [ + "restock-client-snapshot-overwrites-concurrent-purchases", + "catalog-tie-breaks-in-reverse-alphabetical-order--01-core", + "signin-binds-the-second-client-to-a-different-account", + "direct-purchases-are-attributed-to-the-system-account", + "review-purchase-eligibility-is-not-checked", + "stock-view-keeps-pre-reconnect-snapshot", + "cancelled-order-remains-in-revenue-invariant", + "recommendations-ignore-pending-purchases", + "completed-restock-remains-pending", + "customer-profile-view-leaks-another-account", + "notification-preferences-leak-across-accounts", + "stock-alert-is-sent-after-every-restock", + "nonpositive-cart-quantity-is-treated-as-removal", + "stored-support-replies-are-hidden-after-reload", + "support-history-leaks-to-signed-out-visitors" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-add0647be965-spacetime-mutation.runs/r1-workers/w3.stdout.log", + "stderr": "ecommerce-l3-add0647be965-spacetime-mutation.runs/r1-workers/w3.stderr.log" + } + }, + { + "index": 3, + "runIndex": 3, + "artifact": "ecommerce-l3-add0647be965-spacetime-mutation.runs/r1-workers/w4.json", + "mutationIds": [ + "signup-binds-the-new-account-to-the-admin-session", + "purchase-does-not-update-ranking-count", + "checkout-does-not-empty-the-basic-cart", + "direct-restock-does-not-require-an-admin", + "eligible-review-is-accepted-without-being-stored", + "open-review-list-snapshots-on-selection", + "operator-authorization-allows-customer-transfer", + "purchases-do-not-affect-best-sellers", + "pending-restock-timer-is-static", + "faceted-search-ignores-category", + "customers-can-create-promotions", + "stock-alerts-are-visible-to-other-customers", + "admin-restock-preserves-existing-stock", + "saving-notification-preferences-resets-the-toggles", + "checkout-crash-integrity" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-add0647be965-spacetime-mutation.runs/r1-workers/w4.stdout.log", + "stderr": "ecommerce-l3-add0647be965-spacetime-mutation.runs/r1-workers/w4.stderr.log" + } + }, + { + "index": 4, + "runIndex": 4, + "artifact": "ecommerce-l3-add0647be965-spacetime-mutation.runs/r1-workers/w5.json", + "mutationIds": [ + "duplicate-signup-is-silently-ignored", + "signed-out-purchase-bypasses-account-check", + "new-review-is-accepted-without-being-stored", + "direct-purchase-ignores-the-stored-price", + "cart-line-lookup-ignores-cart-ownership", + "open-review-list-renders-each-review-twice", + "customer-can-ship-order-direct-1-1", + "queue-warehouse-reports-west", + "due-restock-omits-ledger-entry", + "active-search-uses-purchase-ranking", + "promotion-rule-stores-the-wrong-discount", + "support-history-is-lost-on-fresh-account-login", + "direct-review-access-is-not-checked", + "saving-a-staff-role-snaps-the-input-back-to-the-stored-role", + "checkout-crash-durability" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-add0647be965-spacetime-mutation.runs/r1-workers/w5.stdout.log", + "stderr": "ecommerce-l3-add0647be965-spacetime-mutation.runs/r1-workers/w5.stderr.log" + } + }, + { + "index": 5, + "runIndex": 5, + "artifact": "ecommerce-l3-add0647be965-spacetime-mutation.runs/r1-workers/w6.json", + "mutationIds": [ + "signin-does-not-verify-the-password", + "buy-now-creates-orders-without-reserving-stock--01-buying", + "repeat-review-inserts-a-second-row", + "account-state-token-is-not-restored-after-reload", + "purchase-does-not-reserve-stock-last-unit", + "cancel-does-not-restore-stock-feature", + "customer-can-cancel-foreign-order-1-1", + "transfer-creates-stock-during-race", + "cancelled-restock-remains-pending", + "faceted-search-next-page-does-not-advance", + "staff-cannot-open-staff-tools", + "support-history-leaks-across-customers", + "support-history-rows-are-hidden", + "fulfilment-queue-is-frozen-at-page-load" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-add0647be965-spacetime-mutation.runs/r1-workers/w6.stdout.log", + "stderr": "ecommerce-l3-add0647be965-spacetime-mutation.runs/r1-workers/w6.stderr.log" + } + }, + { + "index": 6, + "runIndex": 6, + "artifact": "ecommerce-l3-add0647be965-spacetime-mutation.runs/r1-workers/w7.json", + "mutationIds": [ + "signout-keeps-the-account-session", + "restock-race-records-wrong-order-total", + "review-average-counts-rows-instead-of-ratings", + "reconnect-discards-the-visible-account-state", + "existing-cart-line-does-not-increment", + "cancellation-accounting-loses-stock-restoration", + "ship-acknowledges-without-changing-status", + "catalog-search-ignores-the-query", + "restart-restock-runs-early", + "managed-support-leaks-and-accepts-cross-account-replies", + "customers-can-open-staff-tools", + "visitor-support-reference-is-hidden", + "authorized-restock-does-not-change-stock", + "low-stock-list-is-frozen-at-page-load" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-add0647be965-spacetime-mutation.runs/r1-workers/w7.stdout.log", + "stderr": "ecommerce-l3-add0647be965-spacetime-mutation.runs/r1-workers/w7.stderr.log" + } + }, + { + "index": 7, + "runIndex": 7, + "artifact": "ecommerce-l3-add0647be965-spacetime-mutation.runs/r1-workers/w8.json", + "mutationIds": [ + "session-token-is-not-persisted-for-reload", + "buy-now-records-the-wrong-order-total", + "every-signed-in-customer-is-treated-as-an-admin", + "order-views-return-every-customers-orders", + "checkout-does-not-empty-cart", + "cancel-does-not-restore-stock-fresh-client", + "progression-customer-sees-fulfilment-content", + "admin-total-stock-is-not-rendered", + "catalog-product-is-not-published", + "managed-support-replies-are-empty", + "administrator-role-assignment-is-discarded", + "support-assignment-is-discarded", + "low-stock-threshold-is-two-units", + "category-totals-are-frozen-at-page-load" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-add0647be965-spacetime-mutation.runs/r1-workers/w8.stdout.log", + "stderr": "ecommerce-l3-add0647be965-spacetime-mutation.runs/r1-workers/w8.stderr.log" + } + } + ] + } + ], + "stable": true, + "sameImage": true, + "sameHarness": true, + "harnessSha256": "d423f94e24aae42fa30fcd169e387eeddf15f50c35cebdb4b461044b98e466f8", + "qualifiedCheckKeys": [ + "ecommerce.feature.accounts.accounts.1a", + "ecommerce.feature.accounts.accounts.1b", + "ecommerce.feature.accounts.accounts.1c", + "ecommerce.feature.accounts.accounts.1d", + "ecommerce.feature.cart-checkout.cart.4a", + "ecommerce.feature.cart-checkout.cart.4d", + "ecommerce.feature.catalog.catalog-ranking.2b", + "ecommerce.feature.catalog.catalog-search.2d", + "ecommerce.feature.catalog.catalog-values.2a", + "ecommerce.feature.purchasing.purchase-order.3c", + "ecommerce.feature.reviews.reviews.6a", + "ecommerce.feature.warehouse-admin.admin-write.103a", + "ecommerce.feature.warehouse-admin.warehouse-view.7b", + "ecommerce.inventory-operations.operational-views.5c", + "ecommerce.inventory-operations.operational-views.5d", + "ecommerce.inventory-operations.operational-views.5e", + "ecommerce.inventory-operations.operational-views.5f", + "ecommerce.inventory-operations.shipping-accounting.202e", + "ecommerce.inventory-operations.stock-conservation.202a", + "ecommerce.inventory-operations.stock-conservation.202b", + "ecommerce.inventory-operations.stock-conservation.202c", + "ecommerce.inventory-operations.stock-conservation.202d", + "ecommerce.inventory-operations.warehouse-transfer.2a", + "ecommerce.l3.deferred-access.scheduled-work-access.317a", + "ecommerce.l3.deferred-durability.restart-survival.311a", + "ecommerce.l3.deferred-integrity.exactly-once.311a", + "ecommerce.l3.scheduled-restocks.scheduled-restocks.302a", + "ecommerce.l3.scheduled-restocks.scheduled-restocks.305a", + "ecommerce.l3.scheduled-restocks.scheduled-restocks.306a", + "ecommerce.l3.server-time.server-time.312a", + "ecommerce.operations-access.fulfilment-queue.1b", + "ecommerce.operations-access.fulfilment-queue.1c", + "ecommerce.operations-access.operator-authorization.201a", + "ecommerce.operations-access.operator-authorization.201c", + "ecommerce.operations-access.order-owner.204a", + "ecommerce.progression.catalog-management.catalog-management.622a", + "ecommerce.progression.catalog-management.catalog-management.622b", + "ecommerce.progression.customer-profile.customer-profile.620c", + "ecommerce.progression.faceted-search.faceted-search.401a", + "ecommerce.progression.faceted-search.faceted-search.402a", + "ecommerce.progression.managed-support.managed-support.613c", + "ecommerce.progression.notification-preferences.notification-preferences.630c", + "ecommerce.progression.promotion-rules.promotion-rule-values.620a", + "ecommerce.progression.review-access-specifications.review-eligibility-direct.618a", + "ecommerce.progression.staff-access.staff-access.601a", + "ecommerce.progression.staff-roles.staff-roles.621c", + "ecommerce.progression.stock-alerts.stock-alert-delivery.631c", + "ecommerce.progression.support-history.support-history.612c", + "ecommerce.progression.support-intake.support-intake.610a", + "ecommerce.progression.support-triage.support-assignment.611a", + "ecommerce.progression.support-triage.support-priority.611b", + "ecommerce.progression.support-triage.support-status.611c", + "ecommerce.returns-pricing.cancellation-and-return.3a", + "ecommerce.returns-pricing.cancellation-and-return.3b", + "ecommerce.returns-pricing.refund-accounting.203a", + "ecommerce.spec.access-control.cart-boundary.109a", + "ecommerce.spec.access-control.cart-boundary.109b", + "ecommerce.spec.access-control.customer-profile-privacy.620b", + "ecommerce.spec.access-control.fulfilment-area-boundary.1d", + "ecommerce.spec.access-control.managed-support-privacy.613b", + "ecommerce.spec.access-control.notification-preferences-privacy.630b", + "ecommerce.spec.access-control.order-ownership.106a", + "ecommerce.spec.access-control.promotion-management-boundary.620b", + "ecommerce.spec.access-control.purchase-attribution.102a", + "ecommerce.spec.access-control.purchase-session.101a", + "ecommerce.spec.access-control.review-eligibility.108a", + "ecommerce.spec.access-control.review-eligibility.108b", + "ecommerce.spec.access-control.signed-out-purchase.3a", + "ecommerce.spec.access-control.staff-area-boundary.601b", + "ecommerce.spec.access-control.staff-role-boundary.621b", + "ecommerce.spec.access-control.staff-role-revocation.621d", + "ecommerce.spec.access-control.stock-alert-privacy.631b", + "ecommerce.spec.access-control.support-history-logout.612d", + "ecommerce.spec.access-control.support-history-privacy.612b", + "ecommerce.spec.access-control.warehouse-area-boundary.7a", + "ecommerce.spec.access-control.warehouse-write-boundary.103b", + "ecommerce.spec.concurrency-safety.duplicate-checkout.203a", + "ecommerce.spec.concurrency-safety.duplicate-checkout.203b", + "ecommerce.spec.concurrency-safety.last-unit.201a", + "ecommerce.spec.concurrency-safety.last-unit.201b", + "ecommerce.spec.concurrency-safety.last-unit.201c", + "ecommerce.spec.concurrency-safety.restock-race.202a", + "ecommerce.spec.external-data-sync.external-stock.901a", + "ecommerce.spec.external-data-sync.external-stock.901c", + "ecommerce.spec.external-data-sync.external-stock.901d", + "ecommerce.spec.live-state.fulfilment-queue.1a", + "ecommerce.spec.live-state.inventory-dashboard.5a", + "ecommerce.spec.live-state.managed-support.613a", + "ecommerce.spec.live-state.open-list.902a", + "ecommerce.spec.live-state.purchase-stock.3b", + "ecommerce.spec.live-state.ranking.2c", + "ecommerce.spec.live-state.rating.6c", + "ecommerce.spec.live-state.sales-dashboard.5b", + "ecommerce.spec.live-state.shared-cart.4c", + "ecommerce.spec.live-state.stock-transfers.2b", + "ecommerce.spec.live-state.warehouse-stock.7c", + "ecommerce.spec.search-ordering.search-ordering.402b", + "ecommerce.spec.state-durability.account-state-recovery.105a", + "ecommerce.spec.state-durability.account-state-recovery.105b", + "ecommerce.spec.state-durability.cart-reload.4b", + "ecommerce.spec.state-durability.checkout-crash-durability.910b", + "ecommerce.spec.state-durability.checkout-crash-integrity.910a", + "ecommerce.spec.state-durability.customer-profile-reload.620a", + "ecommerce.spec.state-durability.notification-preferences-reload.630a", + "ecommerce.spec.state-durability.session-reload.1e", + "ecommerce.spec.state-durability.staff-role-reload.621a", + "ecommerce.spec.state-durability.support-history-reload.612a", + "ecommerce.spec.transactional-integrity.books-balance.107a", + "ecommerce.spec.transactional-integrity.books-balance.107b", + "ecommerce.spec.transactional-integrity.server-price.104a", + "ecommerce.spec.transactional-integrity.stock-alert-deduplication.631a", + "ecommerce.spec.transactional-integrity.stock-transfer-overdraw.2c", + "ecommerce.spec.transactional-integrity.unique-review.6b" + ], + "featureCatalog": { + "contentSha256": "a8c0bf542ec57e0189b99cd3e70a9cea7373c2c83bf4867e11f2c76db329a087", + "id": "ecommerce.questlines" + }, + "diagnostic": false, + "ok": true + } +} diff --git a/tools/stack-bench/qualification-evidence/ecommerce-l3-78ccb6966/spacetime-reference.json b/tools/stack-bench/qualification-evidence/ecommerce-l3-78ccb6966/spacetime-reference.json new file mode 100644 index 00000000000..1c096e3925f --- /dev/null +++ b/tools/stack-bench/qualification-evidence/ecommerce-l3-78ccb6966/spacetime-reference.json @@ -0,0 +1,735 @@ +{ + "artifactSchemaVersion": 2, + "kind": "reference_qualification", + "id": "reference-live-spacetime-20260917171218-30-reference", + "attempt": { + "id": "reference-live-spacetime-20260917171218-30-reference", + "parentId": null + }, + "timestamps": { + "startedAt": "2026-09-17T17:12:18.472Z", + "completedAt": "2026-09-17T18:05:40.088Z" + }, + "identities": { + "engine": { + "id": "stack-bench", + "sha256": "6562a1f38ed757804dc8a6f70ac3c36bb71e7cfd257fbfb4aacd1c30a7412bea" + }, + "recipe": { + "id": "ecommerce.progression-catalog", + "sha256": "add0647be965132c0b9702c5db3ba8265a01b0edc8ca5d820cc152e4ceeb5a89" + }, + "fixture": { + "id": "ecommerce-reference-spacetime", + "sha256": "7ba1f548e89f461b95b5caf843b0fbcf2b81278428d02869d7f47e1a199eaf6e" + }, + "calibration": { + "id": "ecommerce.dependency-l3-calibration", + "sha256": "dc4bf3e29e5d5040becf8fdd846e7d3fd6419a27cb766c8c93a75f19f66c664b" + }, + "experiment": null, + "agentAdapter": null, + "stackAdapter": { + "id": "spacetime", + "sha256": null + }, + "packs": [] + }, + "payload": { + "fixture": "ecommerce-reference-spacetime", + "fixtureSha256": "7ba1f548e89f461b95b5caf843b0fbcf2b81278428d02869d7f47e1a199eaf6e", + "requiredRepetitions": 1, + "isolation": "docker", + "runner": { + "schemaVersion": 1, + "mode": "appliance", + "platform": "linux", + "architecture": "x64", + "hostname": "docker-desktop", + "dockerEngineVersion": "29.6.2", + "dockerOs": "linux", + "dockerArchitecture": "x86_64", + "kernelVersion": "6.6.87.2-microsoft-standard-WSL2", + "cpuCount": 32, + "memoryBytes": 49232842752, + "containersRunning": 13, + "packageRegistry": "http://127.0.0.1:4873/" + }, + "qualificationScope": { + "checksSha256": "64d4f2af43f951e8c70d61ed1e64baf5f376ce3fa6031b1a9d79db2bd48aeaff", + "executableSha256": "56429eab8bd9ba42bcc31e94d2c598364abda6aa1b909fb60fc1a54a61a64530", + "kind": "reference", + "mutationSha256": null, + "recipe": { + "contentSha256": "add0647be965132c0b9702c5db3ba8265a01b0edc8ca5d820cc152e4ceeb5a89", + "id": "ecommerce.progression-catalog" + }, + "schemaVersion": 3, + "stack": { + "id": "spacetime", + "reference": { + "id": "ecommerce-reference-spacetime", + "sourceSha256": "7ba1f548e89f461b95b5caf843b0fbcf2b81278428d02869d7f47e1a199eaf6e" + }, + "version": "1.4.0" + }, + "sha256": "04ddaaafc4b8ff37fa01e28db4fe99531f6fac335477cfd620590019f2aa7aae" + }, + "mutationControl": false, + "runs": [ + { + "repetition": 1, + "output": "ecommerce-l3-add0647be965-spacetime-mutation.runs/r1", + "durationMs": 2304660, + "processError": null, + "harnessSha256Before": "d423f94e24aae42fa30fcd169e387eeddf15f50c35cebdb4b461044b98e466f8", + "harnessSha256After": "d423f94e24aae42fa30fcd169e387eeddf15f50c35cebdb4b461044b98e466f8", + "ok": true, + "failures": [], + "runId": "ecommerce-spacetime-run0-20260917171219-de875061", + "score": "182/182", + "imageId": "sha256:32ff9a9e519ba9d1af2fe72f24622caa8ca7a9f2baf2338c6b1e0435e6ac5455", + "criteria": 113, + "zeroPointCriteria": 0, + "fingerprint": "0d6c57cc6ec1dd08dd5409aa619f28d1aa7c74e27644a80dd2312a0038b978cc", + "outcome": "passed", + "packRuntime": { + "schemaVersion": 1, + "metric": "pack-check-wall-clock-sum-v1", + "packs": [ + { + "id": "ecommerce.feature.accounts", + "checkCount": 4, + "setupRuntimeMs": 894, + "criterionRuntimeMs": 15047, + "measuredRuntimeMs": 15941, + "budget": { + "status": "bounded", + "maxRuntimeMs": 18000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.cart", + "checkCount": 1, + "setupRuntimeMs": 410, + "criterionRuntimeMs": 6040, + "measuredRuntimeMs": 6450, + "budget": { + "status": "bounded", + "maxRuntimeMs": 42000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.catalog-discovery", + "checkCount": 2, + "setupRuntimeMs": 1, + "criterionRuntimeMs": 2239, + "measuredRuntimeMs": 2240, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.catalog-items", + "checkCount": 1, + "setupRuntimeMs": 0, + "criterionRuntimeMs": 260, + "measuredRuntimeMs": 260, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.checkout", + "checkCount": 1, + "setupRuntimeMs": 410, + "criterionRuntimeMs": 6258, + "measuredRuntimeMs": 6668, + "budget": { + "status": "bounded", + "maxRuntimeMs": 42000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.purchasing", + "checkCount": 1, + "setupRuntimeMs": 401, + "criterionRuntimeMs": 1184, + "measuredRuntimeMs": 1585, + "budget": { + "status": "bounded", + "maxRuntimeMs": 24000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.reviews", + "checkCount": 1, + "setupRuntimeMs": 1679, + "criterionRuntimeMs": 351, + "measuredRuntimeMs": 2030, + "budget": { + "status": "bounded", + "maxRuntimeMs": 22000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.warehouse-admin", + "checkCount": 2, + "setupRuntimeMs": 1222, + "criterionRuntimeMs": 4632, + "measuredRuntimeMs": 5854, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.inventory-dashboard", + "checkCount": 1, + "setupRuntimeMs": 5352, + "criterionRuntimeMs": 8, + "measuredRuntimeMs": 5360, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.order-cancellation-features", + "checkCount": 2, + "setupRuntimeMs": 746, + "criterionRuntimeMs": 12119, + "measuredRuntimeMs": 12865, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.recommendations", + "checkCount": 1, + "setupRuntimeMs": 313, + "criterionRuntimeMs": 5141, + "measuredRuntimeMs": 5454, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.sales-dashboard", + "checkCount": 2, + "setupRuntimeMs": 1915, + "criterionRuntimeMs": 5754, + "measuredRuntimeMs": 7669, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.stock-transfers-features", + "checkCount": 1, + "setupRuntimeMs": 352, + "criterionRuntimeMs": 1834, + "measuredRuntimeMs": 2186, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.deferred-access-specifications", + "checkCount": 1, + "setupRuntimeMs": 20776, + "criterionRuntimeMs": 4248, + "measuredRuntimeMs": 25024, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.deferred-durability-specifications", + "checkCount": 1, + "setupRuntimeMs": 124952, + "criterionRuntimeMs": 42098, + "measuredRuntimeMs": 167050, + "budget": { + "status": "bounded", + "maxRuntimeMs": 720000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.deferred-integrity-specifications", + "checkCount": 1, + "setupRuntimeMs": 40477, + "criterionRuntimeMs": 37125, + "measuredRuntimeMs": 77602, + "budget": { + "status": "bounded", + "maxRuntimeMs": 400000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.scheduled-restocks-features", + "checkCount": 3, + "setupRuntimeMs": 61395, + "criterionRuntimeMs": 70364, + "measuredRuntimeMs": 131759, + "budget": { + "status": "bounded", + "maxRuntimeMs": 150000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.server-time-specifications", + "checkCount": 1, + "setupRuntimeMs": 25897, + "criterionRuntimeMs": 115051, + "measuredRuntimeMs": 140948, + "budget": { + "status": "bounded", + "maxRuntimeMs": 300000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.cancellation-accounting-specifications", + "checkCount": 1, + "setupRuntimeMs": 662, + "criterionRuntimeMs": 12161, + "measuredRuntimeMs": 12823, + "budget": { + "status": "bounded", + "maxRuntimeMs": 24000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.catalog-management", + "checkCount": 2, + "setupRuntimeMs": 3623, + "criterionRuntimeMs": 23, + "measuredRuntimeMs": 3646, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.customer-profile", + "checkCount": 1, + "setupRuntimeMs": 463, + "criterionRuntimeMs": 5074, + "measuredRuntimeMs": 5537, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.faceted-search", + "checkCount": 2, + "setupRuntimeMs": 44379, + "criterionRuntimeMs": 25588, + "measuredRuntimeMs": 69967, + "budget": { + "status": "bounded", + "maxRuntimeMs": 141000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.fulfilment-queue", + "checkCount": 2, + "setupRuntimeMs": 1010, + "criterionRuntimeMs": 28622, + "measuredRuntimeMs": 29632, + "budget": { + "status": "bounded", + "maxRuntimeMs": 76000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.inventory-conservation-specifications", + "checkCount": 5, + "setupRuntimeMs": 2159, + "criterionRuntimeMs": 55507, + "measuredRuntimeMs": 57666, + "budget": { + "status": "bounded", + "maxRuntimeMs": 138000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.managed-support", + "checkCount": 1, + "setupRuntimeMs": 850, + "criterionRuntimeMs": 6845, + "measuredRuntimeMs": 7695, + "budget": { + "status": "bounded", + "maxRuntimeMs": 55000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.notification-preferences", + "checkCount": 1, + "setupRuntimeMs": 612, + "criterionRuntimeMs": 5075, + "measuredRuntimeMs": 5687, + "budget": { + "status": "bounded", + "maxRuntimeMs": 40000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.operations-access-specifications", + "checkCount": 3, + "setupRuntimeMs": 9554, + "criterionRuntimeMs": 38253, + "measuredRuntimeMs": 47807, + "budget": { + "status": "bounded", + "maxRuntimeMs": 98000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.promotion-rules", + "checkCount": 1, + "setupRuntimeMs": 581, + "criterionRuntimeMs": 369, + "measuredRuntimeMs": 950, + "budget": { + "status": "bounded", + "maxRuntimeMs": 45000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.review-access-specifications", + "checkCount": 1, + "setupRuntimeMs": 3893, + "criterionRuntimeMs": 7169, + "measuredRuntimeMs": 11062, + "budget": { + "status": "bounded", + "maxRuntimeMs": 62000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.staff-access", + "checkCount": 1, + "setupRuntimeMs": 0, + "criterionRuntimeMs": 645, + "measuredRuntimeMs": 645, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.staff-roles", + "checkCount": 1, + "setupRuntimeMs": 486, + "criterionRuntimeMs": 30, + "measuredRuntimeMs": 516, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.stock-alerts", + "checkCount": 1, + "setupRuntimeMs": 5786, + "criterionRuntimeMs": 12418, + "measuredRuntimeMs": 18204, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.support-history", + "checkCount": 1, + "setupRuntimeMs": 743, + "criterionRuntimeMs": 1425, + "measuredRuntimeMs": 2168, + "budget": { + "status": "bounded", + "maxRuntimeMs": 50000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.support-intake", + "checkCount": 1, + "setupRuntimeMs": 0, + "criterionRuntimeMs": 442, + "measuredRuntimeMs": 442, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.support-triage", + "checkCount": 3, + "setupRuntimeMs": 705, + "criterionRuntimeMs": 10806, + "measuredRuntimeMs": 11511, + "budget": { + "status": "bounded", + "maxRuntimeMs": 45000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.access-control", + "checkCount": 21, + "setupRuntimeMs": 28144, + "criterionRuntimeMs": 224590, + "measuredRuntimeMs": 252734, + "budget": { + "status": "bounded", + "maxRuntimeMs": 464000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.concurrency-safety", + "checkCount": 6, + "setupRuntimeMs": 28113, + "criterionRuntimeMs": 64430, + "measuredRuntimeMs": 92543, + "budget": { + "status": "bounded", + "maxRuntimeMs": 125000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.external-data-sync", + "checkCount": 3, + "setupRuntimeMs": 611, + "criterionRuntimeMs": 33083, + "measuredRuntimeMs": 33694, + "budget": { + "status": "bounded", + "maxRuntimeMs": 105000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.live-state", + "checkCount": 11, + "setupRuntimeMs": 20587, + "criterionRuntimeMs": 7328, + "measuredRuntimeMs": 27915, + "budget": { + "status": "bounded", + "maxRuntimeMs": 184000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.search-ordering", + "checkCount": 1, + "setupRuntimeMs": 21514, + "criterionRuntimeMs": 5226, + "measuredRuntimeMs": 26740, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.state-durability", + "checkCount": 10, + "setupRuntimeMs": 8929, + "criterionRuntimeMs": 57873, + "measuredRuntimeMs": 66802, + "budget": { + "status": "bounded", + "maxRuntimeMs": 768000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.transactional-integrity", + "checkCount": 6, + "setupRuntimeMs": 25270, + "criterionRuntimeMs": 35966, + "measuredRuntimeMs": 61236, + "budget": { + "status": "bounded", + "maxRuntimeMs": 100000 + }, + "exceeded": false + } + ] + }, + "mutations": null + } + ], + "stable": true, + "sameImage": true, + "sameHarness": true, + "harnessSha256": "d423f94e24aae42fa30fcd169e387eeddf15f50c35cebdb4b461044b98e466f8", + "qualifiedCheckKeys": [ + "ecommerce.feature.accounts.accounts.1a", + "ecommerce.feature.accounts.accounts.1b", + "ecommerce.feature.accounts.accounts.1c", + "ecommerce.feature.accounts.accounts.1d", + "ecommerce.feature.cart-checkout.cart.4a", + "ecommerce.feature.cart-checkout.cart.4d", + "ecommerce.feature.catalog.catalog-ranking.2b", + "ecommerce.feature.catalog.catalog-search.2d", + "ecommerce.feature.catalog.catalog-values.2a", + "ecommerce.feature.purchasing.purchase-order.3c", + "ecommerce.feature.reviews.reviews.6a", + "ecommerce.feature.warehouse-admin.admin-write.103a", + "ecommerce.feature.warehouse-admin.warehouse-view.7b", + "ecommerce.inventory-operations.operational-views.5c", + "ecommerce.inventory-operations.operational-views.5d", + "ecommerce.inventory-operations.operational-views.5e", + "ecommerce.inventory-operations.operational-views.5f", + "ecommerce.inventory-operations.shipping-accounting.202e", + "ecommerce.inventory-operations.stock-conservation.202a", + "ecommerce.inventory-operations.stock-conservation.202b", + "ecommerce.inventory-operations.stock-conservation.202c", + "ecommerce.inventory-operations.stock-conservation.202d", + "ecommerce.inventory-operations.warehouse-transfer.2a", + "ecommerce.l3.deferred-access.scheduled-work-access.317a", + "ecommerce.l3.deferred-durability.restart-survival.311a", + "ecommerce.l3.deferred-integrity.exactly-once.311a", + "ecommerce.l3.scheduled-restocks.scheduled-restocks.302a", + "ecommerce.l3.scheduled-restocks.scheduled-restocks.305a", + "ecommerce.l3.scheduled-restocks.scheduled-restocks.306a", + "ecommerce.l3.server-time.server-time.312a", + "ecommerce.operations-access.fulfilment-queue.1b", + "ecommerce.operations-access.fulfilment-queue.1c", + "ecommerce.operations-access.operator-authorization.201a", + "ecommerce.operations-access.operator-authorization.201c", + "ecommerce.operations-access.order-owner.204a", + "ecommerce.progression.catalog-management.catalog-management.622a", + "ecommerce.progression.catalog-management.catalog-management.622b", + "ecommerce.progression.customer-profile.customer-profile.620c", + "ecommerce.progression.faceted-search.faceted-search.401a", + "ecommerce.progression.faceted-search.faceted-search.402a", + "ecommerce.progression.managed-support.managed-support.613c", + "ecommerce.progression.notification-preferences.notification-preferences.630c", + "ecommerce.progression.promotion-rules.promotion-rule-values.620a", + "ecommerce.progression.review-access-specifications.review-eligibility-direct.618a", + "ecommerce.progression.staff-access.staff-access.601a", + "ecommerce.progression.staff-roles.staff-roles.621c", + "ecommerce.progression.stock-alerts.stock-alert-delivery.631c", + "ecommerce.progression.support-history.support-history.612c", + "ecommerce.progression.support-intake.support-intake.610a", + "ecommerce.progression.support-triage.support-assignment.611a", + "ecommerce.progression.support-triage.support-priority.611b", + "ecommerce.progression.support-triage.support-status.611c", + "ecommerce.returns-pricing.cancellation-and-return.3a", + "ecommerce.returns-pricing.cancellation-and-return.3b", + "ecommerce.returns-pricing.refund-accounting.203a", + "ecommerce.spec.access-control.cart-boundary.109a", + "ecommerce.spec.access-control.cart-boundary.109b", + "ecommerce.spec.access-control.customer-profile-privacy.620b", + "ecommerce.spec.access-control.fulfilment-area-boundary.1d", + "ecommerce.spec.access-control.managed-support-privacy.613b", + "ecommerce.spec.access-control.notification-preferences-privacy.630b", + "ecommerce.spec.access-control.order-ownership.106a", + "ecommerce.spec.access-control.promotion-management-boundary.620b", + "ecommerce.spec.access-control.purchase-attribution.102a", + "ecommerce.spec.access-control.purchase-session.101a", + "ecommerce.spec.access-control.review-eligibility.108a", + "ecommerce.spec.access-control.review-eligibility.108b", + "ecommerce.spec.access-control.signed-out-purchase.3a", + "ecommerce.spec.access-control.staff-area-boundary.601b", + "ecommerce.spec.access-control.staff-role-boundary.621b", + "ecommerce.spec.access-control.staff-role-revocation.621d", + "ecommerce.spec.access-control.stock-alert-privacy.631b", + "ecommerce.spec.access-control.support-history-logout.612d", + "ecommerce.spec.access-control.support-history-privacy.612b", + "ecommerce.spec.access-control.warehouse-area-boundary.7a", + "ecommerce.spec.access-control.warehouse-write-boundary.103b", + "ecommerce.spec.concurrency-safety.duplicate-checkout.203a", + "ecommerce.spec.concurrency-safety.duplicate-checkout.203b", + "ecommerce.spec.concurrency-safety.last-unit.201a", + "ecommerce.spec.concurrency-safety.last-unit.201b", + "ecommerce.spec.concurrency-safety.last-unit.201c", + "ecommerce.spec.concurrency-safety.restock-race.202a", + "ecommerce.spec.external-data-sync.external-stock.901a", + "ecommerce.spec.external-data-sync.external-stock.901c", + "ecommerce.spec.external-data-sync.external-stock.901d", + "ecommerce.spec.live-state.fulfilment-queue.1a", + "ecommerce.spec.live-state.inventory-dashboard.5a", + "ecommerce.spec.live-state.managed-support.613a", + "ecommerce.spec.live-state.open-list.902a", + "ecommerce.spec.live-state.purchase-stock.3b", + "ecommerce.spec.live-state.ranking.2c", + "ecommerce.spec.live-state.rating.6c", + "ecommerce.spec.live-state.sales-dashboard.5b", + "ecommerce.spec.live-state.shared-cart.4c", + "ecommerce.spec.live-state.stock-transfers.2b", + "ecommerce.spec.live-state.warehouse-stock.7c", + "ecommerce.spec.search-ordering.search-ordering.402b", + "ecommerce.spec.state-durability.account-state-recovery.105a", + "ecommerce.spec.state-durability.account-state-recovery.105b", + "ecommerce.spec.state-durability.cart-reload.4b", + "ecommerce.spec.state-durability.checkout-crash-durability.910b", + "ecommerce.spec.state-durability.checkout-crash-integrity.910a", + "ecommerce.spec.state-durability.customer-profile-reload.620a", + "ecommerce.spec.state-durability.notification-preferences-reload.630a", + "ecommerce.spec.state-durability.session-reload.1e", + "ecommerce.spec.state-durability.staff-role-reload.621a", + "ecommerce.spec.state-durability.support-history-reload.612a", + "ecommerce.spec.transactional-integrity.books-balance.107a", + "ecommerce.spec.transactional-integrity.books-balance.107b", + "ecommerce.spec.transactional-integrity.server-price.104a", + "ecommerce.spec.transactional-integrity.stock-alert-deduplication.631a", + "ecommerce.spec.transactional-integrity.stock-transfer-overdraw.2c", + "ecommerce.spec.transactional-integrity.unique-review.6b" + ], + "featureCatalog": { + "contentSha256": "a8c0bf542ec57e0189b99cd3e70a9cea7373c2c83bf4867e11f2c76db329a087", + "id": "ecommerce.questlines" + }, + "diagnostic": false, + "ok": true + } +} diff --git a/tools/stack-bench/qualification-evidence/ecommerce-l3-7cd96d01b/mongodb-mutation.json b/tools/stack-bench/qualification-evidence/ecommerce-l3-7cd96d01b/mongodb-mutation.json new file mode 100644 index 00000000000..3b481e09c40 --- /dev/null +++ b/tools/stack-bench/qualification-evidence/ecommerce-l3-7cd96d01b/mongodb-mutation.json @@ -0,0 +1,955 @@ +{ + "artifactSchemaVersion": 2, + "kind": "reference_qualification", + "id": "reference-live-mongodb-20260917222453-30", + "attempt": { + "id": "reference-live-mongodb-20260917222453-30", + "parentId": null + }, + "timestamps": { + "startedAt": "2026-09-17T22:24:53.425Z", + "completedAt": "2026-09-17T23:19:41.461Z" + }, + "identities": { + "engine": { + "id": "stack-bench", + "sha256": "ee2e27156ab1080f508abaf810d87c114aba21846768f33897be0581aeb7a795" + }, + "recipe": { + "id": "ecommerce.progression-catalog", + "sha256": "104589b973c1e7dd1a2410659759989eb0de08b16efeda3131777f82858a0a8b" + }, + "fixture": { + "id": "ecommerce-reference-mongodb", + "sha256": "0d21bbc4b2768f4077a81d676f0d4c87a65067dda8f2c5ffeb2fa9208381dc7e" + }, + "calibration": { + "id": "ecommerce.dependency-l3-calibration", + "sha256": "1b0b4927efbcabbaf8975f4ffbb0ebc77d6af2679fc0f9cac9ef492d751933e0" + }, + "experiment": null, + "agentAdapter": null, + "stackAdapter": { + "id": "mongodb", + "sha256": null + }, + "packs": [] + }, + "payload": { + "fixture": "ecommerce-reference-mongodb", + "fixtureSha256": "0d21bbc4b2768f4077a81d676f0d4c87a65067dda8f2c5ffeb2fa9208381dc7e", + "requiredRepetitions": 1, + "isolation": "docker", + "runner": { + "schemaVersion": 1, + "mode": "appliance", + "platform": "linux", + "architecture": "x64", + "hostname": "docker-desktop", + "dockerEngineVersion": "29.6.2", + "dockerOs": "linux", + "dockerArchitecture": "x86_64", + "kernelVersion": "6.6.87.2-microsoft-standard-WSL2", + "cpuCount": 32, + "memoryBytes": 49232842752, + "containersRunning": 11, + "packageRegistry": "http://127.0.0.1:4873/" + }, + "qualificationScope": { + "checksSha256": "ce9efe7f66ef111ce68dc65dcb22b48e20e4e89e68bd62fb7f7776e6a379f64d", + "executableSha256": "591d84b0d1979e7ffdb6c3145f53cc7c0bf3e4441aa6a10849e1003d87b96b80", + "kind": "mutation", + "mutationSha256": "927e83bd722707a09c763de85f46c8c4bc58e5ce370490a8ddbaaabde6bbcbf7", + "recipe": { + "contentSha256": "104589b973c1e7dd1a2410659759989eb0de08b16efeda3131777f82858a0a8b", + "id": "ecommerce.progression-catalog" + }, + "schemaVersion": 3, + "stack": { + "id": "mongodb", + "reference": { + "id": "ecommerce-reference-mongodb", + "sourceSha256": "0d21bbc4b2768f4077a81d676f0d4c87a65067dda8f2c5ffeb2fa9208381dc7e" + }, + "version": "1.5.0" + }, + "sha256": "500270dd04c14997f90108c3ccc835d56071be6e8d179eb95bc143c12d6bcc19" + }, + "mutationControl": true, + "runs": [ + { + "repetition": 1, + "output": "ecommerce-l3-104589b973c1-mongodb-mutation.runs/r1-workers", + "durationMs": 3287956, + "processError": null, + "harnessSha256Before": "c911977ee8f6b0894c581b7c9d95957441c8052f7404e7ebff17f00cec4d86e5", + "harnessSha256After": "c911977ee8f6b0894c581b7c9d95957441c8052f7404e7ebff17f00cec4d86e5", + "ok": true, + "failures": [], + "runId": "reference-live-mongodb-20260917222453-30", + "score": "183/183", + "imageId": "sha256:32ff9a9e519ba9d1af2fe72f24622caa8ca7a9f2baf2338c6b1e0435e6ac5455", + "criteria": 114, + "zeroPointCriteria": 0, + "fingerprint": "3197a361efd9c27179e97087a9e9e342476520f9b1ae1fef4e358b08893058a8", + "outcome": "passed", + "packRuntime": { + "schemaVersion": 1, + "metric": "pack-check-wall-clock-sum-v1", + "packs": [ + { + "id": "ecommerce.feature.accounts", + "checkCount": 4, + "setupRuntimeMs": 1250, + "criterionRuntimeMs": 15374, + "measuredRuntimeMs": 16624, + "budget": { + "status": "bounded", + "maxRuntimeMs": 18000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.cart", + "checkCount": 1, + "setupRuntimeMs": 657, + "criterionRuntimeMs": 6067, + "measuredRuntimeMs": 6724, + "budget": { + "status": "bounded", + "maxRuntimeMs": 42000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.catalog-discovery", + "checkCount": 2, + "setupRuntimeMs": 0, + "criterionRuntimeMs": 1949, + "measuredRuntimeMs": 1949, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.catalog-items", + "checkCount": 1, + "setupRuntimeMs": 1, + "criterionRuntimeMs": 267, + "measuredRuntimeMs": 268, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.checkout", + "checkCount": 1, + "setupRuntimeMs": 657, + "criterionRuntimeMs": 10771, + "measuredRuntimeMs": 11428, + "budget": { + "status": "bounded", + "maxRuntimeMs": 42000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.purchasing", + "checkCount": 1, + "setupRuntimeMs": 422, + "criterionRuntimeMs": 1173, + "measuredRuntimeMs": 1595, + "budget": { + "status": "bounded", + "maxRuntimeMs": 24000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.reviews", + "checkCount": 1, + "setupRuntimeMs": 2618, + "criterionRuntimeMs": 366, + "measuredRuntimeMs": 2984, + "budget": { + "status": "bounded", + "maxRuntimeMs": 22000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.warehouse-admin", + "checkCount": 2, + "setupRuntimeMs": 1670, + "criterionRuntimeMs": 4315, + "measuredRuntimeMs": 5985, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.inventory-dashboard", + "checkCount": 1, + "setupRuntimeMs": 4477, + "criterionRuntimeMs": 9, + "measuredRuntimeMs": 4486, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.order-cancellation-features", + "checkCount": 2, + "setupRuntimeMs": 1135, + "criterionRuntimeMs": 16351, + "measuredRuntimeMs": 17486, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.recommendations", + "checkCount": 1, + "setupRuntimeMs": 338, + "criterionRuntimeMs": 5195, + "measuredRuntimeMs": 5533, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.sales-dashboard", + "checkCount": 2, + "setupRuntimeMs": 2286, + "criterionRuntimeMs": 5047, + "measuredRuntimeMs": 7333, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.stock-transfers-features", + "checkCount": 1, + "setupRuntimeMs": 554, + "criterionRuntimeMs": 2900, + "measuredRuntimeMs": 3454, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.deferred-access-specifications", + "checkCount": 1, + "setupRuntimeMs": 21076, + "criterionRuntimeMs": 4257, + "measuredRuntimeMs": 25333, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.deferred-durability-specifications", + "checkCount": 1, + "setupRuntimeMs": 128758, + "criterionRuntimeMs": 39436, + "measuredRuntimeMs": 168194, + "budget": { + "status": "bounded", + "maxRuntimeMs": 720000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.deferred-integrity-specifications", + "checkCount": 1, + "setupRuntimeMs": 43121, + "criterionRuntimeMs": 39435, + "measuredRuntimeMs": 82556, + "budget": { + "status": "bounded", + "maxRuntimeMs": 400000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.scheduled-restocks-features", + "checkCount": 3, + "setupRuntimeMs": 61617, + "criterionRuntimeMs": 69231, + "measuredRuntimeMs": 130848, + "budget": { + "status": "bounded", + "maxRuntimeMs": 150000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.server-time-specifications", + "checkCount": 1, + "setupRuntimeMs": 28275, + "criterionRuntimeMs": 112943, + "measuredRuntimeMs": 141218, + "budget": { + "status": "bounded", + "maxRuntimeMs": 300000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.cancellation-accounting-specifications", + "checkCount": 1, + "setupRuntimeMs": 931, + "criterionRuntimeMs": 12550, + "measuredRuntimeMs": 13481, + "budget": { + "status": "bounded", + "maxRuntimeMs": 24000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.catalog-management", + "checkCount": 2, + "setupRuntimeMs": 3426, + "criterionRuntimeMs": 23, + "measuredRuntimeMs": 3449, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.customer-profile", + "checkCount": 1, + "setupRuntimeMs": 510, + "criterionRuntimeMs": 5073, + "measuredRuntimeMs": 5583, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.faceted-search", + "checkCount": 2, + "setupRuntimeMs": 43543, + "criterionRuntimeMs": 25618, + "measuredRuntimeMs": 69161, + "budget": { + "status": "bounded", + "maxRuntimeMs": 141000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.fulfilment-queue", + "checkCount": 2, + "setupRuntimeMs": 1603, + "criterionRuntimeMs": 27367, + "measuredRuntimeMs": 28970, + "budget": { + "status": "bounded", + "maxRuntimeMs": 76000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.inventory-conservation-specifications", + "checkCount": 5, + "setupRuntimeMs": 2815, + "criterionRuntimeMs": 64921, + "measuredRuntimeMs": 67736, + "budget": { + "status": "bounded", + "maxRuntimeMs": 138000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.managed-support", + "checkCount": 1, + "setupRuntimeMs": 1138, + "criterionRuntimeMs": 6173, + "measuredRuntimeMs": 7311, + "budget": { + "status": "bounded", + "maxRuntimeMs": 55000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.notification-preferences", + "checkCount": 1, + "setupRuntimeMs": 689, + "criterionRuntimeMs": 5107, + "measuredRuntimeMs": 5796, + "budget": { + "status": "bounded", + "maxRuntimeMs": 40000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.operations-access-specifications", + "checkCount": 3, + "setupRuntimeMs": 10274, + "criterionRuntimeMs": 38843, + "measuredRuntimeMs": 49117, + "budget": { + "status": "bounded", + "maxRuntimeMs": 98000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.promotion-rules", + "checkCount": 1, + "setupRuntimeMs": 637, + "criterionRuntimeMs": 450, + "measuredRuntimeMs": 1087, + "budget": { + "status": "bounded", + "maxRuntimeMs": 45000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.review-access-specifications", + "checkCount": 2, + "setupRuntimeMs": 28819, + "criterionRuntimeMs": 9584, + "measuredRuntimeMs": 38403, + "budget": { + "status": "bounded", + "maxRuntimeMs": 82000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.staff-access", + "checkCount": 1, + "setupRuntimeMs": 0, + "criterionRuntimeMs": 905, + "measuredRuntimeMs": 905, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.staff-roles", + "checkCount": 1, + "setupRuntimeMs": 613, + "criterionRuntimeMs": 32, + "measuredRuntimeMs": 645, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.stock-alerts", + "checkCount": 1, + "setupRuntimeMs": 5295, + "criterionRuntimeMs": 11440, + "measuredRuntimeMs": 16735, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.support-history", + "checkCount": 1, + "setupRuntimeMs": 1019, + "criterionRuntimeMs": 1150, + "measuredRuntimeMs": 2169, + "budget": { + "status": "bounded", + "maxRuntimeMs": 50000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.support-intake", + "checkCount": 1, + "setupRuntimeMs": 0, + "criterionRuntimeMs": 493, + "measuredRuntimeMs": 493, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.support-triage", + "checkCount": 3, + "setupRuntimeMs": 858, + "criterionRuntimeMs": 10109, + "measuredRuntimeMs": 10967, + "budget": { + "status": "bounded", + "maxRuntimeMs": 45000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.access-control", + "checkCount": 21, + "setupRuntimeMs": 31087, + "criterionRuntimeMs": 220056, + "measuredRuntimeMs": 251143, + "budget": { + "status": "bounded", + "maxRuntimeMs": 464000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.concurrency-safety", + "checkCount": 6, + "setupRuntimeMs": 31259, + "criterionRuntimeMs": 73131, + "measuredRuntimeMs": 104390, + "budget": { + "status": "bounded", + "maxRuntimeMs": 125000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.external-data-sync", + "checkCount": 3, + "setupRuntimeMs": 650, + "criterionRuntimeMs": 29629, + "measuredRuntimeMs": 30279, + "budget": { + "status": "bounded", + "maxRuntimeMs": 105000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.live-state", + "checkCount": 11, + "setupRuntimeMs": 81368, + "criterionRuntimeMs": 9700, + "measuredRuntimeMs": 91068, + "budget": { + "status": "bounded", + "maxRuntimeMs": 184000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.search-ordering", + "checkCount": 1, + "setupRuntimeMs": 22255, + "criterionRuntimeMs": 5215, + "measuredRuntimeMs": 27470, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.state-durability", + "checkCount": 10, + "setupRuntimeMs": 126491, + "criterionRuntimeMs": 74643, + "measuredRuntimeMs": 201134, + "budget": { + "status": "bounded", + "maxRuntimeMs": 768000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.transactional-integrity", + "checkCount": 6, + "setupRuntimeMs": 45362, + "criterionRuntimeMs": 39063, + "measuredRuntimeMs": 84425, + "budget": { + "status": "bounded", + "maxRuntimeMs": 100000 + }, + "exceeded": false + } + ] + }, + "mutations": { + "caught": 114, + "total": 114 + }, + "baselineDurationMs": 2261004, + "baselineOutput": "ecommerce-l3-104589b973c1-mongodb-mutation.runs/r1", + "baselineHarnessSha256Before": "c911977ee8f6b0894c581b7c9d95957441c8052f7404e7ebff17f00cec4d86e5", + "baselineHarnessSha256After": "c911977ee8f6b0894c581b7c9d95957441c8052f7404e7ebff17f00cec4d86e5", + "workers": [ + { + "index": 0, + "runIndex": 0, + "artifact": "ecommerce-l3-104589b973c1-mongodb-mutation.runs/r1-workers/w1.json", + "mutationIds": [ + "staff-admin-access-survives-role-removal", + "signed-out-visitor-purchase-is-accepted", + "live-review-average-uses-an-extra-divisor", + "unpurchased-review-is-accepted", + "cancel-does-not-restore-stock-fresh-client", + "progression-customer-sees-fulfilment-content", + "catalog-search-requires-exact-name", + "completed-restock-is-replayed", + "profile-read-is-not-owner-scoped", + "promotion-save-drops-bounded-values", + "stock-alert-repeats-while-in-stock", + "direct-purchase-is-attributed-to-another-account", + "support-history-rows-are-hidden", + "queue-ignores-live-fulfilment-updates", + "review-script-unsafe-render" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-104589b973c1-mongodb-mutation.runs/r1-workers/w1.stdout.log", + "stderr": "ecommerce-l3-104589b973c1-mongodb-mutation.runs/r1-workers/w1.stderr.log" + } + }, + { + "index": 1, + "runIndex": 1, + "artifact": "ecommerce-l3-104589b973c1-mongodb-mutation.runs/r1-workers/w2.json", + "mutationIds": [ + "shipping-counts-sale-twice", + "espresso-stock-row-ignores-live-updates", + "warehouse-view-omits-one-location", + "purchased-review-ui-does-not-submit", + "cancel-restores-stock-but-keeps-pending-status", + "transfer-debits-source-without-crediting-existing-destination", + "catalog-price-is-offset", + "scheduled-restock-countdown-is-fixed", + "faceted-search-ignores-category", + "customer-can-create-promotion", + "stock-alerts-are-not-owner-scoped", + "concurrent-cart-add-does-not-increment", + "authorized-restock-does-not-change-stock", + "low-stock-boundary-excludes-ten-live", + "review-script-reject-all" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-104589b973c1-mongodb-mutation.runs/r1-workers/w2.stdout.log", + "stderr": "ecommerce-l3-104589b973c1-mongodb-mutation.runs/r1-workers/w2.stderr.log" + } + }, + { + "index": 2, + "runIndex": 2, + "artifact": "ecommerce-l3-104589b973c1-mongodb-mutation.runs/r1-workers/w3.json", + "mutationIds": [ + "signup-does-not-expose-created-account", + "restock-race-records-wrong-order-total", + "unauthenticated-purchase-defaults-to-admin", + "external-stock-polling-disabled", + "cancelled-order-remains-in-revenue-feature", + "recommendations-ignore-pending-purchases", + "staff-can-see-admin-navigation", + "due-restock-does-not-change-stock", + "active-search-uses-purchase-ranking", + "staff-signin-loses-staff-role", + "support-history-is-lost-on-server-restart", + "checkout-claim-is-not-atomic", + "initial-dashboard-load-omits-low-stock", + "live-admin-updates-keep-stale-category-totals" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-104589b973c1-mongodb-mutation.runs/r1-workers/w3.stdout.log", + "stderr": "ecommerce-l3-104589b973c1-mongodb-mutation.runs/r1-workers/w3.stderr.log" + } + }, + { + "index": 3, + "runIndex": 3, + "artifact": "ecommerce-l3-104589b973c1-mongodb-mutation.runs/r1-workers/w4.json", + "mutationIds": [ + "duplicate-signup-reports-success", + "purchase-order-uses-zero-price", + "direct-purchase-total-ignores-store-price", + "server-restart-disables-catalog-recovery", + "cancelled-order-remains-in-revenue-invariant", + "purchases-do-not-affect-best-sellers", + "staff-can-use-direct-restock", + "cancelled-restock-remains-pending", + "pagination-repeats-first-page", + "customer-signin-gains-staff-role", + "support-history-is-not-owner-scoped", + "last-unit-allows-negative-stock", + "category-totals-skip-the-newest-order", + "overdraw-transfer-is-accepted" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-104589b973c1-mongodb-mutation.runs/r1-workers/w4.stdout.log", + "stderr": "ecommerce-l3-104589b973c1-mongodb-mutation.runs/r1-workers/w4.stderr.log" + } + }, + { + "index": 4, + "runIndex": 4, + "artifact": "ecommerce-l3-104589b973c1-mongodb-mutation.runs/r1-workers/w5.json", + "mutationIds": [ + "signin-skips-password-verification", + "reload-hydrates-an-empty-cart", + "cart-hydration-loses-account-state", + "reconnect-generation-ignores-current-catalog", + "operator-authorization-allows-customer-transfer", + "queue-warehouse-reports-west", + "restock-adds-the-wrong-quantity", + "server-time-restock-never-completes", + "managed-support-live-refresh-keeps-stale-tickets", + "role-assignment-drops-role", + "support-intake-returns-no-reference", + "purchase-read-write-loses-concurrent-stock", + "profile-summary-frozen-at-open", + "transfer-totals-omit-destination-credit-live" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-104589b973c1-mongodb-mutation.runs/r1-workers/w5.stdout.log", + "stderr": "ecommerce-l3-104589b973c1-mongodb-mutation.runs/r1-workers/w5.stderr.log" + } + }, + { + "index": 5, + "runIndex": 5, + "artifact": "ecommerce-l3-104589b973c1-mongodb-mutation.runs/r1-workers/w6.json", + "mutationIds": [ + "signout-keeps-current-account", + "shared-cart-live-events-ignored", + "reconnect-hydration-loses-account-state", + "open-review-list-ignores-live-update", + "customer-can-ship-order-direct-1-1", + "cart-repeat-does-not-increment", + "transfer-creates-stock-during-race", + "catalog-product-name-is-not-published", + "managed-support-allows-another-customer", + "staff-role-write-precedes-denial", + "support-triage-discards-updates", + "purchase-does-not-reduce-warehouse-stock", + "support-replies-present-at-open-are-hidden", + "support-history-leaks-to-signed-out-visitors" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-104589b973c1-mongodb-mutation.runs/r1-workers/w6.stdout.log", + "stderr": "ecommerce-l3-104589b973c1-mongodb-mutation.runs/r1-workers/w6.stderr.log" + } + }, + { + "index": 6, + "runIndex": 6, + "artifact": "ecommerce-l3-104589b973c1-mongodb-mutation.runs/r1-workers/w7.json", + "mutationIds": [ + "session-token-not-persisted", + "review-comment-is-not-persisted", + "order-history-is-not-owner-scoped", + "cancel-does-not-restore-stock-feature", + "customer-can-cancel-foreign-order-1-1", + "checkout-leaves-cart-claimed", + "customer-can-cancel-scheduled-restock", + "catalog-variants-are-discarded", + "notification-preference-is-not-saved", + "staff-can-assign-roles", + "cart-add-uses-another-account-cart", + "restock-does-not-increase-stock", + "notification-toggle-frozen-at-open", + "checkout-crash-integrity" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-104589b973c1-mongodb-mutation.runs/r1-workers/w7.stdout.log", + "stderr": "ecommerce-l3-104589b973c1-mongodb-mutation.runs/r1-workers/w7.stderr.log" + } + }, + { + "index": 7, + "runIndex": 7, + "artifact": "ecommerce-l3-104589b973c1-mongodb-mutation.runs/r1-workers/w8.json", + "mutationIds": [ + "purchase-counts-never-affect-ranking", + "repeat-review-uses-a-new-owner-key", + "revenue-aggregation-ignores-order-totals", + "cancellation-accounting-loses-stock-restoration", + "ship-acknowledges-without-changing-status", + "catalog-initial-ranking-is-reversed", + "scheduled-restock-never-becomes-due-after-restart", + "profile-data-is-lost-on-server-restart", + "notification-preference-is-not-owner-scoped", + "stock-alert-delivery-is-suppressed", + "negative-cart-quantity-is-accepted", + "direct-review-access-is-not-checked", + "role-editor-snaps-back-to-stored-role", + "checkout-crash-durability" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-104589b973c1-mongodb-mutation.runs/r1-workers/w8.stdout.log", + "stderr": "ecommerce-l3-104589b973c1-mongodb-mutation.runs/r1-workers/w8.stderr.log" + } + } + ] + } + ], + "stable": true, + "sameImage": true, + "sameHarness": true, + "harnessSha256": "c911977ee8f6b0894c581b7c9d95957441c8052f7404e7ebff17f00cec4d86e5", + "qualifiedCheckKeys": [ + "ecommerce.feature.accounts.accounts.1a", + "ecommerce.feature.accounts.accounts.1b", + "ecommerce.feature.accounts.accounts.1c", + "ecommerce.feature.accounts.accounts.1d", + "ecommerce.feature.cart-checkout.cart.4a", + "ecommerce.feature.cart-checkout.cart.4d", + "ecommerce.feature.catalog.catalog-ranking.2b", + "ecommerce.feature.catalog.catalog-search.2d", + "ecommerce.feature.catalog.catalog-values.2a", + "ecommerce.feature.purchasing.purchase-order.3c", + "ecommerce.feature.reviews.reviews.6a", + "ecommerce.feature.warehouse-admin.admin-write.103a", + "ecommerce.feature.warehouse-admin.warehouse-view.7b", + "ecommerce.inventory-operations.operational-views.5c", + "ecommerce.inventory-operations.operational-views.5d", + "ecommerce.inventory-operations.operational-views.5e", + "ecommerce.inventory-operations.operational-views.5f", + "ecommerce.inventory-operations.shipping-accounting.202e", + "ecommerce.inventory-operations.stock-conservation.202a", + "ecommerce.inventory-operations.stock-conservation.202b", + "ecommerce.inventory-operations.stock-conservation.202c", + "ecommerce.inventory-operations.stock-conservation.202d", + "ecommerce.inventory-operations.warehouse-transfer.2a", + "ecommerce.l3.deferred-access.scheduled-work-access.317a", + "ecommerce.l3.deferred-durability.restart-survival.311a", + "ecommerce.l3.deferred-integrity.exactly-once.311a", + "ecommerce.l3.scheduled-restocks.scheduled-restocks.302a", + "ecommerce.l3.scheduled-restocks.scheduled-restocks.305a", + "ecommerce.l3.scheduled-restocks.scheduled-restocks.306a", + "ecommerce.l3.server-time.server-time.312a", + "ecommerce.operations-access.fulfilment-queue.1b", + "ecommerce.operations-access.fulfilment-queue.1c", + "ecommerce.operations-access.operator-authorization.201a", + "ecommerce.operations-access.operator-authorization.201c", + "ecommerce.operations-access.order-owner.204a", + "ecommerce.progression.catalog-management.catalog-management.622a", + "ecommerce.progression.catalog-management.catalog-management.622b", + "ecommerce.progression.customer-profile.customer-profile.620c", + "ecommerce.progression.faceted-search.faceted-search.401a", + "ecommerce.progression.faceted-search.faceted-search.402a", + "ecommerce.progression.managed-support.managed-support.613c", + "ecommerce.progression.notification-preferences.notification-preferences.630c", + "ecommerce.progression.promotion-rules.promotion-rule-values.620a", + "ecommerce.progression.review-access-specifications.review-eligibility-direct.618a", + "ecommerce.progression.review-access-specifications.stored-review-script.9180a", + "ecommerce.progression.staff-access.staff-access.601a", + "ecommerce.progression.staff-roles.staff-roles.621c", + "ecommerce.progression.stock-alerts.stock-alert-delivery.631c", + "ecommerce.progression.support-history.support-history.612c", + "ecommerce.progression.support-intake.support-intake.610a", + "ecommerce.progression.support-triage.support-assignment.611a", + "ecommerce.progression.support-triage.support-priority.611b", + "ecommerce.progression.support-triage.support-status.611c", + "ecommerce.returns-pricing.cancellation-and-return.3a", + "ecommerce.returns-pricing.cancellation-and-return.3b", + "ecommerce.returns-pricing.refund-accounting.203a", + "ecommerce.spec.access-control.cart-boundary.109a", + "ecommerce.spec.access-control.cart-boundary.109b", + "ecommerce.spec.access-control.customer-profile-privacy.620b", + "ecommerce.spec.access-control.fulfilment-area-boundary.1d", + "ecommerce.spec.access-control.managed-support-privacy.613b", + "ecommerce.spec.access-control.notification-preferences-privacy.630b", + "ecommerce.spec.access-control.order-ownership.106a", + "ecommerce.spec.access-control.promotion-management-boundary.620b", + "ecommerce.spec.access-control.purchase-attribution.102a", + "ecommerce.spec.access-control.purchase-session.101a", + "ecommerce.spec.access-control.review-eligibility.108a", + "ecommerce.spec.access-control.review-eligibility.108b", + "ecommerce.spec.access-control.signed-out-purchase.3a", + "ecommerce.spec.access-control.staff-area-boundary.601b", + "ecommerce.spec.access-control.staff-role-boundary.621b", + "ecommerce.spec.access-control.staff-role-revocation.621d", + "ecommerce.spec.access-control.stock-alert-privacy.631b", + "ecommerce.spec.access-control.support-history-logout.612d", + "ecommerce.spec.access-control.support-history-privacy.612b", + "ecommerce.spec.access-control.warehouse-area-boundary.7a", + "ecommerce.spec.access-control.warehouse-write-boundary.103b", + "ecommerce.spec.concurrency-safety.duplicate-checkout.203a", + "ecommerce.spec.concurrency-safety.duplicate-checkout.203b", + "ecommerce.spec.concurrency-safety.last-unit.201a", + "ecommerce.spec.concurrency-safety.last-unit.201b", + "ecommerce.spec.concurrency-safety.last-unit.201c", + "ecommerce.spec.concurrency-safety.restock-race.202a", + "ecommerce.spec.external-data-sync.external-stock.901a", + "ecommerce.spec.external-data-sync.external-stock.901c", + "ecommerce.spec.external-data-sync.external-stock.901d", + "ecommerce.spec.live-state.fulfilment-queue.1a", + "ecommerce.spec.live-state.inventory-dashboard.5a", + "ecommerce.spec.live-state.managed-support.613a", + "ecommerce.spec.live-state.open-list.902a", + "ecommerce.spec.live-state.purchase-stock.3b", + "ecommerce.spec.live-state.ranking.2c", + "ecommerce.spec.live-state.rating.6c", + "ecommerce.spec.live-state.sales-dashboard.5b", + "ecommerce.spec.live-state.shared-cart.4c", + "ecommerce.spec.live-state.stock-transfers.2b", + "ecommerce.spec.live-state.warehouse-stock.7c", + "ecommerce.spec.search-ordering.search-ordering.402b", + "ecommerce.spec.state-durability.account-state-recovery.105a", + "ecommerce.spec.state-durability.account-state-recovery.105b", + "ecommerce.spec.state-durability.cart-reload.4b", + "ecommerce.spec.state-durability.checkout-crash-durability.910b", + "ecommerce.spec.state-durability.checkout-crash-integrity.910a", + "ecommerce.spec.state-durability.customer-profile-reload.620a", + "ecommerce.spec.state-durability.notification-preferences-reload.630a", + "ecommerce.spec.state-durability.session-reload.1e", + "ecommerce.spec.state-durability.staff-role-reload.621a", + "ecommerce.spec.state-durability.support-history-reload.612a", + "ecommerce.spec.transactional-integrity.books-balance.107a", + "ecommerce.spec.transactional-integrity.books-balance.107b", + "ecommerce.spec.transactional-integrity.server-price.104a", + "ecommerce.spec.transactional-integrity.stock-alert-deduplication.631a", + "ecommerce.spec.transactional-integrity.stock-transfer-overdraw.2c", + "ecommerce.spec.transactional-integrity.unique-review.6b" + ], + "featureCatalog": { + "contentSha256": "8671f7883c2e5a24474a546ef1517407cd9334258e1a7cfe91e292a9af1952f2", + "id": "ecommerce.questlines" + }, + "diagnostic": false, + "ok": true + } +} diff --git a/tools/stack-bench/qualification-evidence/ecommerce-l3-7cd96d01b/mongodb-reference.json b/tools/stack-bench/qualification-evidence/ecommerce-l3-7cd96d01b/mongodb-reference.json new file mode 100644 index 00000000000..9f5fa416853 --- /dev/null +++ b/tools/stack-bench/qualification-evidence/ecommerce-l3-7cd96d01b/mongodb-reference.json @@ -0,0 +1,736 @@ +{ + "artifactSchemaVersion": 2, + "kind": "reference_qualification", + "id": "reference-live-mongodb-20260917222453-30-reference", + "attempt": { + "id": "reference-live-mongodb-20260917222453-30-reference", + "parentId": null + }, + "timestamps": { + "startedAt": "2026-09-17T22:24:53.425Z", + "completedAt": "2026-09-17T23:19:41.462Z" + }, + "identities": { + "engine": { + "id": "stack-bench", + "sha256": "ee2e27156ab1080f508abaf810d87c114aba21846768f33897be0581aeb7a795" + }, + "recipe": { + "id": "ecommerce.progression-catalog", + "sha256": "104589b973c1e7dd1a2410659759989eb0de08b16efeda3131777f82858a0a8b" + }, + "fixture": { + "id": "ecommerce-reference-mongodb", + "sha256": "0d21bbc4b2768f4077a81d676f0d4c87a65067dda8f2c5ffeb2fa9208381dc7e" + }, + "calibration": { + "id": "ecommerce.dependency-l3-calibration", + "sha256": "1b0b4927efbcabbaf8975f4ffbb0ebc77d6af2679fc0f9cac9ef492d751933e0" + }, + "experiment": null, + "agentAdapter": null, + "stackAdapter": { + "id": "mongodb", + "sha256": null + }, + "packs": [] + }, + "payload": { + "fixture": "ecommerce-reference-mongodb", + "fixtureSha256": "0d21bbc4b2768f4077a81d676f0d4c87a65067dda8f2c5ffeb2fa9208381dc7e", + "requiredRepetitions": 1, + "isolation": "docker", + "runner": { + "schemaVersion": 1, + "mode": "appliance", + "platform": "linux", + "architecture": "x64", + "hostname": "docker-desktop", + "dockerEngineVersion": "29.6.2", + "dockerOs": "linux", + "dockerArchitecture": "x86_64", + "kernelVersion": "6.6.87.2-microsoft-standard-WSL2", + "cpuCount": 32, + "memoryBytes": 49232842752, + "containersRunning": 11, + "packageRegistry": "http://127.0.0.1:4873/" + }, + "qualificationScope": { + "checksSha256": "ce9efe7f66ef111ce68dc65dcb22b48e20e4e89e68bd62fb7f7776e6a379f64d", + "executableSha256": "591d84b0d1979e7ffdb6c3145f53cc7c0bf3e4441aa6a10849e1003d87b96b80", + "kind": "reference", + "mutationSha256": null, + "recipe": { + "contentSha256": "104589b973c1e7dd1a2410659759989eb0de08b16efeda3131777f82858a0a8b", + "id": "ecommerce.progression-catalog" + }, + "schemaVersion": 3, + "stack": { + "id": "mongodb", + "reference": { + "id": "ecommerce-reference-mongodb", + "sourceSha256": "0d21bbc4b2768f4077a81d676f0d4c87a65067dda8f2c5ffeb2fa9208381dc7e" + }, + "version": "1.5.0" + }, + "sha256": "cb10622617f9450c6db2b9ea86bbdec77b5f79179ade79e5c970c2a04f5b3d83" + }, + "mutationControl": false, + "runs": [ + { + "repetition": 1, + "output": "ecommerce-l3-104589b973c1-mongodb-mutation.runs/r1", + "durationMs": 2261004, + "processError": null, + "harnessSha256Before": "c911977ee8f6b0894c581b7c9d95957441c8052f7404e7ebff17f00cec4d86e5", + "harnessSha256After": "c911977ee8f6b0894c581b7c9d95957441c8052f7404e7ebff17f00cec4d86e5", + "ok": true, + "failures": [], + "runId": "ecommerce-mongodb-run0-20260917222454-810ff5ba", + "score": "183/183", + "imageId": "sha256:32ff9a9e519ba9d1af2fe72f24622caa8ca7a9f2baf2338c6b1e0435e6ac5455", + "criteria": 114, + "zeroPointCriteria": 0, + "fingerprint": "3197a361efd9c27179e97087a9e9e342476520f9b1ae1fef4e358b08893058a8", + "outcome": "passed", + "packRuntime": { + "schemaVersion": 1, + "metric": "pack-check-wall-clock-sum-v1", + "packs": [ + { + "id": "ecommerce.feature.accounts", + "checkCount": 4, + "setupRuntimeMs": 1250, + "criterionRuntimeMs": 15374, + "measuredRuntimeMs": 16624, + "budget": { + "status": "bounded", + "maxRuntimeMs": 18000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.cart", + "checkCount": 1, + "setupRuntimeMs": 657, + "criterionRuntimeMs": 6067, + "measuredRuntimeMs": 6724, + "budget": { + "status": "bounded", + "maxRuntimeMs": 42000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.catalog-discovery", + "checkCount": 2, + "setupRuntimeMs": 0, + "criterionRuntimeMs": 1949, + "measuredRuntimeMs": 1949, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.catalog-items", + "checkCount": 1, + "setupRuntimeMs": 1, + "criterionRuntimeMs": 267, + "measuredRuntimeMs": 268, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.checkout", + "checkCount": 1, + "setupRuntimeMs": 657, + "criterionRuntimeMs": 10771, + "measuredRuntimeMs": 11428, + "budget": { + "status": "bounded", + "maxRuntimeMs": 42000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.purchasing", + "checkCount": 1, + "setupRuntimeMs": 422, + "criterionRuntimeMs": 1173, + "measuredRuntimeMs": 1595, + "budget": { + "status": "bounded", + "maxRuntimeMs": 24000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.reviews", + "checkCount": 1, + "setupRuntimeMs": 2618, + "criterionRuntimeMs": 366, + "measuredRuntimeMs": 2984, + "budget": { + "status": "bounded", + "maxRuntimeMs": 22000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.warehouse-admin", + "checkCount": 2, + "setupRuntimeMs": 1670, + "criterionRuntimeMs": 4315, + "measuredRuntimeMs": 5985, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.inventory-dashboard", + "checkCount": 1, + "setupRuntimeMs": 4477, + "criterionRuntimeMs": 9, + "measuredRuntimeMs": 4486, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.order-cancellation-features", + "checkCount": 2, + "setupRuntimeMs": 1135, + "criterionRuntimeMs": 16351, + "measuredRuntimeMs": 17486, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.recommendations", + "checkCount": 1, + "setupRuntimeMs": 338, + "criterionRuntimeMs": 5195, + "measuredRuntimeMs": 5533, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.sales-dashboard", + "checkCount": 2, + "setupRuntimeMs": 2286, + "criterionRuntimeMs": 5047, + "measuredRuntimeMs": 7333, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.stock-transfers-features", + "checkCount": 1, + "setupRuntimeMs": 554, + "criterionRuntimeMs": 2900, + "measuredRuntimeMs": 3454, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.deferred-access-specifications", + "checkCount": 1, + "setupRuntimeMs": 21076, + "criterionRuntimeMs": 4257, + "measuredRuntimeMs": 25333, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.deferred-durability-specifications", + "checkCount": 1, + "setupRuntimeMs": 128758, + "criterionRuntimeMs": 39436, + "measuredRuntimeMs": 168194, + "budget": { + "status": "bounded", + "maxRuntimeMs": 720000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.deferred-integrity-specifications", + "checkCount": 1, + "setupRuntimeMs": 43121, + "criterionRuntimeMs": 39435, + "measuredRuntimeMs": 82556, + "budget": { + "status": "bounded", + "maxRuntimeMs": 400000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.scheduled-restocks-features", + "checkCount": 3, + "setupRuntimeMs": 61617, + "criterionRuntimeMs": 69231, + "measuredRuntimeMs": 130848, + "budget": { + "status": "bounded", + "maxRuntimeMs": 150000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.server-time-specifications", + "checkCount": 1, + "setupRuntimeMs": 28275, + "criterionRuntimeMs": 112943, + "measuredRuntimeMs": 141218, + "budget": { + "status": "bounded", + "maxRuntimeMs": 300000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.cancellation-accounting-specifications", + "checkCount": 1, + "setupRuntimeMs": 931, + "criterionRuntimeMs": 12550, + "measuredRuntimeMs": 13481, + "budget": { + "status": "bounded", + "maxRuntimeMs": 24000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.catalog-management", + "checkCount": 2, + "setupRuntimeMs": 3426, + "criterionRuntimeMs": 23, + "measuredRuntimeMs": 3449, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.customer-profile", + "checkCount": 1, + "setupRuntimeMs": 510, + "criterionRuntimeMs": 5073, + "measuredRuntimeMs": 5583, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.faceted-search", + "checkCount": 2, + "setupRuntimeMs": 43543, + "criterionRuntimeMs": 25618, + "measuredRuntimeMs": 69161, + "budget": { + "status": "bounded", + "maxRuntimeMs": 141000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.fulfilment-queue", + "checkCount": 2, + "setupRuntimeMs": 1603, + "criterionRuntimeMs": 27367, + "measuredRuntimeMs": 28970, + "budget": { + "status": "bounded", + "maxRuntimeMs": 76000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.inventory-conservation-specifications", + "checkCount": 5, + "setupRuntimeMs": 2815, + "criterionRuntimeMs": 64921, + "measuredRuntimeMs": 67736, + "budget": { + "status": "bounded", + "maxRuntimeMs": 138000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.managed-support", + "checkCount": 1, + "setupRuntimeMs": 1138, + "criterionRuntimeMs": 6173, + "measuredRuntimeMs": 7311, + "budget": { + "status": "bounded", + "maxRuntimeMs": 55000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.notification-preferences", + "checkCount": 1, + "setupRuntimeMs": 689, + "criterionRuntimeMs": 5107, + "measuredRuntimeMs": 5796, + "budget": { + "status": "bounded", + "maxRuntimeMs": 40000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.operations-access-specifications", + "checkCount": 3, + "setupRuntimeMs": 10274, + "criterionRuntimeMs": 38843, + "measuredRuntimeMs": 49117, + "budget": { + "status": "bounded", + "maxRuntimeMs": 98000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.promotion-rules", + "checkCount": 1, + "setupRuntimeMs": 637, + "criterionRuntimeMs": 450, + "measuredRuntimeMs": 1087, + "budget": { + "status": "bounded", + "maxRuntimeMs": 45000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.review-access-specifications", + "checkCount": 2, + "setupRuntimeMs": 28819, + "criterionRuntimeMs": 9584, + "measuredRuntimeMs": 38403, + "budget": { + "status": "bounded", + "maxRuntimeMs": 82000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.staff-access", + "checkCount": 1, + "setupRuntimeMs": 0, + "criterionRuntimeMs": 905, + "measuredRuntimeMs": 905, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.staff-roles", + "checkCount": 1, + "setupRuntimeMs": 613, + "criterionRuntimeMs": 32, + "measuredRuntimeMs": 645, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.stock-alerts", + "checkCount": 1, + "setupRuntimeMs": 5295, + "criterionRuntimeMs": 11440, + "measuredRuntimeMs": 16735, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.support-history", + "checkCount": 1, + "setupRuntimeMs": 1019, + "criterionRuntimeMs": 1150, + "measuredRuntimeMs": 2169, + "budget": { + "status": "bounded", + "maxRuntimeMs": 50000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.support-intake", + "checkCount": 1, + "setupRuntimeMs": 0, + "criterionRuntimeMs": 493, + "measuredRuntimeMs": 493, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.support-triage", + "checkCount": 3, + "setupRuntimeMs": 858, + "criterionRuntimeMs": 10109, + "measuredRuntimeMs": 10967, + "budget": { + "status": "bounded", + "maxRuntimeMs": 45000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.access-control", + "checkCount": 21, + "setupRuntimeMs": 31087, + "criterionRuntimeMs": 220056, + "measuredRuntimeMs": 251143, + "budget": { + "status": "bounded", + "maxRuntimeMs": 464000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.concurrency-safety", + "checkCount": 6, + "setupRuntimeMs": 31259, + "criterionRuntimeMs": 73131, + "measuredRuntimeMs": 104390, + "budget": { + "status": "bounded", + "maxRuntimeMs": 125000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.external-data-sync", + "checkCount": 3, + "setupRuntimeMs": 650, + "criterionRuntimeMs": 29629, + "measuredRuntimeMs": 30279, + "budget": { + "status": "bounded", + "maxRuntimeMs": 105000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.live-state", + "checkCount": 11, + "setupRuntimeMs": 81368, + "criterionRuntimeMs": 9700, + "measuredRuntimeMs": 91068, + "budget": { + "status": "bounded", + "maxRuntimeMs": 184000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.search-ordering", + "checkCount": 1, + "setupRuntimeMs": 22255, + "criterionRuntimeMs": 5215, + "measuredRuntimeMs": 27470, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.state-durability", + "checkCount": 10, + "setupRuntimeMs": 126491, + "criterionRuntimeMs": 74643, + "measuredRuntimeMs": 201134, + "budget": { + "status": "bounded", + "maxRuntimeMs": 768000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.transactional-integrity", + "checkCount": 6, + "setupRuntimeMs": 45362, + "criterionRuntimeMs": 39063, + "measuredRuntimeMs": 84425, + "budget": { + "status": "bounded", + "maxRuntimeMs": 100000 + }, + "exceeded": false + } + ] + }, + "mutations": null + } + ], + "stable": true, + "sameImage": true, + "sameHarness": true, + "harnessSha256": "c911977ee8f6b0894c581b7c9d95957441c8052f7404e7ebff17f00cec4d86e5", + "qualifiedCheckKeys": [ + "ecommerce.feature.accounts.accounts.1a", + "ecommerce.feature.accounts.accounts.1b", + "ecommerce.feature.accounts.accounts.1c", + "ecommerce.feature.accounts.accounts.1d", + "ecommerce.feature.cart-checkout.cart.4a", + "ecommerce.feature.cart-checkout.cart.4d", + "ecommerce.feature.catalog.catalog-ranking.2b", + "ecommerce.feature.catalog.catalog-search.2d", + "ecommerce.feature.catalog.catalog-values.2a", + "ecommerce.feature.purchasing.purchase-order.3c", + "ecommerce.feature.reviews.reviews.6a", + "ecommerce.feature.warehouse-admin.admin-write.103a", + "ecommerce.feature.warehouse-admin.warehouse-view.7b", + "ecommerce.inventory-operations.operational-views.5c", + "ecommerce.inventory-operations.operational-views.5d", + "ecommerce.inventory-operations.operational-views.5e", + "ecommerce.inventory-operations.operational-views.5f", + "ecommerce.inventory-operations.shipping-accounting.202e", + "ecommerce.inventory-operations.stock-conservation.202a", + "ecommerce.inventory-operations.stock-conservation.202b", + "ecommerce.inventory-operations.stock-conservation.202c", + "ecommerce.inventory-operations.stock-conservation.202d", + "ecommerce.inventory-operations.warehouse-transfer.2a", + "ecommerce.l3.deferred-access.scheduled-work-access.317a", + "ecommerce.l3.deferred-durability.restart-survival.311a", + "ecommerce.l3.deferred-integrity.exactly-once.311a", + "ecommerce.l3.scheduled-restocks.scheduled-restocks.302a", + "ecommerce.l3.scheduled-restocks.scheduled-restocks.305a", + "ecommerce.l3.scheduled-restocks.scheduled-restocks.306a", + "ecommerce.l3.server-time.server-time.312a", + "ecommerce.operations-access.fulfilment-queue.1b", + "ecommerce.operations-access.fulfilment-queue.1c", + "ecommerce.operations-access.operator-authorization.201a", + "ecommerce.operations-access.operator-authorization.201c", + "ecommerce.operations-access.order-owner.204a", + "ecommerce.progression.catalog-management.catalog-management.622a", + "ecommerce.progression.catalog-management.catalog-management.622b", + "ecommerce.progression.customer-profile.customer-profile.620c", + "ecommerce.progression.faceted-search.faceted-search.401a", + "ecommerce.progression.faceted-search.faceted-search.402a", + "ecommerce.progression.managed-support.managed-support.613c", + "ecommerce.progression.notification-preferences.notification-preferences.630c", + "ecommerce.progression.promotion-rules.promotion-rule-values.620a", + "ecommerce.progression.review-access-specifications.review-eligibility-direct.618a", + "ecommerce.progression.review-access-specifications.stored-review-script.9180a", + "ecommerce.progression.staff-access.staff-access.601a", + "ecommerce.progression.staff-roles.staff-roles.621c", + "ecommerce.progression.stock-alerts.stock-alert-delivery.631c", + "ecommerce.progression.support-history.support-history.612c", + "ecommerce.progression.support-intake.support-intake.610a", + "ecommerce.progression.support-triage.support-assignment.611a", + "ecommerce.progression.support-triage.support-priority.611b", + "ecommerce.progression.support-triage.support-status.611c", + "ecommerce.returns-pricing.cancellation-and-return.3a", + "ecommerce.returns-pricing.cancellation-and-return.3b", + "ecommerce.returns-pricing.refund-accounting.203a", + "ecommerce.spec.access-control.cart-boundary.109a", + "ecommerce.spec.access-control.cart-boundary.109b", + "ecommerce.spec.access-control.customer-profile-privacy.620b", + "ecommerce.spec.access-control.fulfilment-area-boundary.1d", + "ecommerce.spec.access-control.managed-support-privacy.613b", + "ecommerce.spec.access-control.notification-preferences-privacy.630b", + "ecommerce.spec.access-control.order-ownership.106a", + "ecommerce.spec.access-control.promotion-management-boundary.620b", + "ecommerce.spec.access-control.purchase-attribution.102a", + "ecommerce.spec.access-control.purchase-session.101a", + "ecommerce.spec.access-control.review-eligibility.108a", + "ecommerce.spec.access-control.review-eligibility.108b", + "ecommerce.spec.access-control.signed-out-purchase.3a", + "ecommerce.spec.access-control.staff-area-boundary.601b", + "ecommerce.spec.access-control.staff-role-boundary.621b", + "ecommerce.spec.access-control.staff-role-revocation.621d", + "ecommerce.spec.access-control.stock-alert-privacy.631b", + "ecommerce.spec.access-control.support-history-logout.612d", + "ecommerce.spec.access-control.support-history-privacy.612b", + "ecommerce.spec.access-control.warehouse-area-boundary.7a", + "ecommerce.spec.access-control.warehouse-write-boundary.103b", + "ecommerce.spec.concurrency-safety.duplicate-checkout.203a", + "ecommerce.spec.concurrency-safety.duplicate-checkout.203b", + "ecommerce.spec.concurrency-safety.last-unit.201a", + "ecommerce.spec.concurrency-safety.last-unit.201b", + "ecommerce.spec.concurrency-safety.last-unit.201c", + "ecommerce.spec.concurrency-safety.restock-race.202a", + "ecommerce.spec.external-data-sync.external-stock.901a", + "ecommerce.spec.external-data-sync.external-stock.901c", + "ecommerce.spec.external-data-sync.external-stock.901d", + "ecommerce.spec.live-state.fulfilment-queue.1a", + "ecommerce.spec.live-state.inventory-dashboard.5a", + "ecommerce.spec.live-state.managed-support.613a", + "ecommerce.spec.live-state.open-list.902a", + "ecommerce.spec.live-state.purchase-stock.3b", + "ecommerce.spec.live-state.ranking.2c", + "ecommerce.spec.live-state.rating.6c", + "ecommerce.spec.live-state.sales-dashboard.5b", + "ecommerce.spec.live-state.shared-cart.4c", + "ecommerce.spec.live-state.stock-transfers.2b", + "ecommerce.spec.live-state.warehouse-stock.7c", + "ecommerce.spec.search-ordering.search-ordering.402b", + "ecommerce.spec.state-durability.account-state-recovery.105a", + "ecommerce.spec.state-durability.account-state-recovery.105b", + "ecommerce.spec.state-durability.cart-reload.4b", + "ecommerce.spec.state-durability.checkout-crash-durability.910b", + "ecommerce.spec.state-durability.checkout-crash-integrity.910a", + "ecommerce.spec.state-durability.customer-profile-reload.620a", + "ecommerce.spec.state-durability.notification-preferences-reload.630a", + "ecommerce.spec.state-durability.session-reload.1e", + "ecommerce.spec.state-durability.staff-role-reload.621a", + "ecommerce.spec.state-durability.support-history-reload.612a", + "ecommerce.spec.transactional-integrity.books-balance.107a", + "ecommerce.spec.transactional-integrity.books-balance.107b", + "ecommerce.spec.transactional-integrity.server-price.104a", + "ecommerce.spec.transactional-integrity.stock-alert-deduplication.631a", + "ecommerce.spec.transactional-integrity.stock-transfer-overdraw.2c", + "ecommerce.spec.transactional-integrity.unique-review.6b" + ], + "featureCatalog": { + "contentSha256": "8671f7883c2e5a24474a546ef1517407cd9334258e1a7cfe91e292a9af1952f2", + "id": "ecommerce.questlines" + }, + "diagnostic": false, + "ok": true + } +} diff --git a/tools/stack-bench/qualification-evidence/ecommerce-l3-7cd96d01b/null.json b/tools/stack-bench/qualification-evidence/ecommerce-l3-7cd96d01b/null.json new file mode 100644 index 00000000000..38914a80b8b --- /dev/null +++ b/tools/stack-bench/qualification-evidence/ecommerce-l3-7cd96d01b/null.json @@ -0,0 +1,1697 @@ +{ + "artifactSchemaVersion": 2, + "kind": "null_control", + "id": "null-control-2026-09-17T22-24-54-645Z", + "attempt": { + "id": "null-control-2026-09-17T22-24-54-645Z", + "parentId": null + }, + "timestamps": { + "startedAt": "2026-09-17T22:24:54.645Z", + "completedAt": "2026-09-17T22:32:40.333Z" + }, + "identities": { + "engine": { + "id": "stack-bench", + "sha256": "ee2e27156ab1080f508abaf810d87c114aba21846768f33897be0581aeb7a795" + }, + "recipe": { + "id": "ecommerce.progression-catalog", + "sha256": "104589b973c1e7dd1a2410659759989eb0de08b16efeda3131777f82858a0a8b" + }, + "fixture": null, + "calibration": { + "id": "ecommerce.dependency-l3-calibration", + "sha256": "1b0b4927efbcabbaf8975f4ffbb0ebc77d6af2679fc0f9cac9ef492d751933e0" + }, + "experiment": null, + "agentAdapter": null, + "stackAdapter": null, + "packs": [] + }, + "payload": { + "durationMs": 465688, + "runner": { + "schemaVersion": 1, + "mode": "appliance", + "platform": "linux", + "architecture": "x64", + "hostname": "docker-desktop", + "dockerEngineVersion": "29.6.2", + "dockerOs": "linux", + "dockerArchitecture": "x86_64", + "kernelVersion": "6.6.87.2-microsoft-standard-WSL2", + "cpuCount": 32, + "memoryBytes": 49232842752, + "containersRunning": 21, + "packageRegistry": "http://127.0.0.1:4873/" + }, + "qualificationScope": { + "checksSha256": "ce9efe7f66ef111ce68dc65dcb22b48e20e4e89e68bd62fb7f7776e6a379f64d", + "executableSha256": "5be2702ae8e22cf920720c40f387c6937ebe594e26997b9ca4c88f0d377ef4c8", + "kind": "null", + "mutationSha256": null, + "recipe": { + "contentSha256": "104589b973c1e7dd1a2410659759989eb0de08b16efeda3131777f82858a0a8b", + "id": "ecommerce.progression-catalog" + }, + "schemaVersion": 3, + "stack": null, + "sha256": "3e791bf811b2ac8524962ddb0a8b63a8f7cf57eb2086182f83d29fd8667fd4dc" + }, + "tracks": [ + "ecommerce" + ], + "ok": true, + "summary": { + "criteria": 114, + "points": 183, + "expectedFailures": { + "criteria": 114, + "points": 183 + }, + "expectedFailureStages": { + "setup": { + "criteria": 107, + "points": 173 + }, + "assertion": { + "criteria": 7, + "points": 10 + } + }, + "vacuousPasses": { + "criteria": 0, + "points": 0 + }, + "oracleGaps": { + "criteria": 0, + "points": 0 + }, + "unscored": { + "criteria": 0, + "passed": 0, + "failed": 0, + "inconclusive": 0 + } + }, + "criteria": [ + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-001", + "scenario": "scenarios/01-account-create.json", + "feature": 1, + "featureName": "Accounts", + "criterion": "1a", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "failed", + "failureStage": "assertion", + "detail": "none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-002", + "scenario": "scenarios/01-account-duplicate.json", + "feature": 1, + "featureName": "Accounts", + "criterion": "1b", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-003", + "scenario": "scenarios/01-account-password.json", + "feature": 1, + "featureName": "Accounts", + "criterion": "1c", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-004", + "scenario": "scenarios/01-account-reload.json", + "feature": 1, + "featureName": "Accounts", + "criterion": "1e", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-005", + "scenario": "scenarios/01-account-signout.json", + "feature": 1, + "featureName": "Accounts", + "criterion": "1d", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-006", + "scenario": "scenarios/01-admin-write-staff.json", + "feature": 103, + "featureName": "Only an administrator can restock", + "criterion": "103a", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-006", + "scenario": "scenarios/01-admin-write-staff.json", + "feature": 103, + "featureName": "Only an administrator can restock", + "criterion": "103b", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-007", + "scenario": "scenarios/01-buying.json", + "feature": 3, + "featureName": "Buying", + "criterion": "3b", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-008", + "scenario": "scenarios/01-cart-boundary.json", + "feature": 109, + "featureName": "A cart is nobody else's business", + "criterion": "109a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-008", + "scenario": "scenarios/01-cart-boundary.json", + "feature": 109, + "featureName": "A cart is nobody else's business", + "criterion": "109b", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-009", + "scenario": "scenarios/01-cart.json", + "feature": 4, + "featureName": "Cart belongs to the account", + "criterion": "4b", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-009", + "scenario": "scenarios/01-cart.json", + "feature": 4, + "featureName": "Cart belongs to the account", + "criterion": "4c", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-010", + "scenario": "scenarios/01-catalog-ranking.json", + "feature": 2, + "featureName": "Public catalog ranking", + "criterion": "2b", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "failed", + "failureStage": "assertion", + "detail": "the item-name control entries are not in the required order" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-011", + "scenario": "scenarios/01-catalog-search.json", + "feature": 2, + "featureName": "Public catalog search", + "criterion": "2d", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "failed", + "failureStage": "assertion", + "detail": "the search-input control did not become available in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-012", + "scenario": "scenarios/01-catalog-values.json", + "feature": 2, + "featureName": "Public catalog values", + "criterion": "2a", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "failed", + "failureStage": "assertion", + "detail": "the item-card control matching \"Air Purifier\" did not appear" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-013", + "scenario": "scenarios/01-core.json", + "feature": 2, + "featureName": "Storefront is public and live", + "criterion": "2c", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-014", + "scenario": "scenarios/01-duplicate-checkout.json", + "feature": 203, + "featureName": "One cart, two tabs, one checkout", + "criterion": "203a", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-014", + "scenario": "scenarios/01-duplicate-checkout.json", + "feature": 203, + "featureName": "One cart, two tabs, one checkout", + "criterion": "203b", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-015", + "scenario": "scenarios/01-external-live-sync.json", + "feature": 901, + "featureName": "An open storefront follows a direct database write", + "criterion": "901a", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: the item-stock control inside the item-card control in the entry matching \"Desk Lamp\" did not appear" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-016", + "scenario": "scenarios/01-external-reconnect-sync.json", + "feature": 901, + "featureName": "A reconnecting storefront catches up to an external write", + "criterion": "901d", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: the item-stock control inside the item-card control in the entry matching \"Desk Lamp\" did not appear" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-018", + "scenario": "scenarios/01-external-server-restart-sync.json", + "feature": 901, + "featureName": "An open storefront catches up after its server restarts", + "criterion": "901c", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: the item-stock control inside the item-card control in the entry matching \"Desk Lamp\" did not appear" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-019", + "scenario": "scenarios/01-last-unit.json", + "feature": 201, + "featureName": "The last unit is sold once", + "criterion": "201a", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-019", + "scenario": "scenarios/01-last-unit.json", + "feature": 201, + "featureName": "The last unit is sold once", + "criterion": "201c", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-019", + "scenario": "scenarios/01-last-unit.json", + "feature": 201, + "featureName": "The last unit is sold once", + "criterion": "201b", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-020", + "scenario": "scenarios/01-order-ownership.json", + "feature": 106, + "featureName": "One customer's orders are not another's", + "criterion": "106a", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-021", + "scenario": "scenarios/01-purchase-attribution.json", + "feature": 102, + "featureName": "Purchases are attributed to whoever made them", + "criterion": "102a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-022", + "scenario": "scenarios/01-purchase-session.json", + "feature": 101, + "featureName": "Purchase requires an account", + "criterion": "101a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-023", + "scenario": "scenarios/01-restock-race.json", + "feature": 202, + "featureName": "A restock during a rush is not lost", + "criterion": "202a", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-024", + "scenario": "scenarios/01-review-eligibility.json", + "feature": 108, + "featureName": "A review is a claim about a purchase", + "criterion": "108a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-024", + "scenario": "scenarios/01-review-eligibility.json", + "feature": 108, + "featureName": "A review is a claim about a purchase", + "criterion": "108b", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-025", + "scenario": "scenarios/01-review-rating-live.json", + "feature": 6, + "featureName": "Reviews", + "criterion": "6c", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-026", + "scenario": "scenarios/01-review-uniqueness.json", + "feature": 6, + "featureName": "Reviews", + "criterion": "6b", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-027", + "scenario": "scenarios/01-review-visibility.json", + "feature": 6, + "featureName": "Reviews", + "criterion": "6a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-028", + "scenario": "scenarios/01-server-price.json", + "feature": 104, + "featureName": "The price is the store's to set", + "criterion": "104a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-029", + "scenario": "scenarios/01-warehouse-admin-staff.json", + "feature": 7, + "featureName": "Admin and warehouses", + "criterion": "7a", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-029", + "scenario": "scenarios/01-warehouse-admin-staff.json", + "feature": 7, + "featureName": "Admin and warehouses", + "criterion": "7b", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-030", + "scenario": "scenarios/01-warehouse-stock-live-staff.json", + "feature": 7, + "featureName": "Warehouse stock stays live", + "criterion": "7c", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-032", + "scenario": "scenarios/02-fulfilment-access.json", + "feature": 1, + "featureName": "Fulfilment area access", + "criterion": "1d", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-033", + "scenario": "scenarios/02-fulfilment-live.json", + "feature": 1, + "featureName": "Live fulfilment queue", + "criterion": "1a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-034", + "scenario": "scenarios/02-fulfilment-ship.json", + "feature": 1, + "featureName": "Ship a pending order", + "criterion": "1c", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-035", + "scenario": "scenarios/02-invariants.json", + "feature": 203, + "featureName": "The books still balance once money can flow backwards", + "criterion": "203a", + "points": 3, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-037", + "scenario": "scenarios/02-low-stock.json", + "feature": 5, + "featureName": "The low-stock view", + "criterion": "5e", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-037", + "scenario": "scenarios/02-low-stock.json", + "feature": 5, + "featureName": "The low-stock view", + "criterion": "5a", + "points": 3, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-038", + "scenario": "scenarios/02-operational-best-sellers.json", + "feature": 5, + "featureName": "Signed-out best sellers", + "criterion": "5d", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-039", + "scenario": "scenarios/02-operational-category-totals.json", + "feature": 5, + "featureName": "Category sales totals", + "criterion": "5f", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-039", + "scenario": "scenarios/02-operational-category-totals.json", + "feature": 5, + "featureName": "Category sales totals", + "criterion": "5b", + "points": 3, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-040", + "scenario": "scenarios/02-operational-recommendations.json", + "feature": 5, + "featureName": "Customer recommendations", + "criterion": "5c", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-041", + "scenario": "scenarios/02-order-cancellation-core.json", + "feature": 3, + "featureName": "Cancel a pending order", + "criterion": "3a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-042", + "scenario": "scenarios/02-order-cancellation-history.json", + "feature": 3, + "featureName": "Cancellation history", + "criterion": "3b", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-044", + "scenario": "scenarios/02-queue-warehouse.json", + "feature": 1, + "featureName": "Fulfilment queue", + "criterion": "1b", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-045", + "scenario": "scenarios/02-self-contained.json", + "feature": 202, + "featureName": "Stock recovery is durable across clients", + "criterion": "202b", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-045", + "scenario": "scenarios/02-self-contained.json", + "feature": 202, + "featureName": "Stock recovery is durable across clients", + "criterion": "202c", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-046", + "scenario": "scenarios/02-server-actions.json", + "feature": 201, + "featureName": "Shipping requires an operator", + "criterion": "201c", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-046", + "scenario": "scenarios/02-server-actions.json", + "feature": 202, + "featureName": "Stock is conserved while operations overlap", + "criterion": "202d", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-046", + "scenario": "scenarios/02-server-actions.json", + "feature": 204, + "featureName": "An order belongs to the person who placed it", + "criterion": "204a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-047", + "scenario": "scenarios/02-strengthened.json", + "feature": 2, + "featureName": "Moving stock between warehouses", + "criterion": "2a", + "points": 3, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-047", + "scenario": "scenarios/02-strengthened.json", + "feature": 201, + "featureName": "Operating the store requires authorization", + "criterion": "201a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-047", + "scenario": "scenarios/02-strengthened.json", + "feature": 202, + "featureName": "Stock is conserved however it moves", + "criterion": "202a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-048", + "scenario": "scenarios/02-transfer-overdraw.json", + "feature": 2, + "featureName": "Moving stock between warehouses", + "criterion": "2c", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-049", + "scenario": "scenarios/02-transfer-totals.json", + "feature": 2, + "featureName": "Warehouse totals", + "criterion": "2b", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-051", + "scenario": "scenarios/03-deferred-access.json", + "feature": 317, + "featureName": "Customers cannot manage scheduled restocks", + "criterion": "317a", + "points": 3, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-052", + "scenario": "scenarios/03-deferred-durability.json", + "feature": 311, + "featureName": "A scheduled restock survives restart", + "criterion": "311a", + "points": 4, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-053", + "scenario": "scenarios/03-deferred-integrity.json", + "feature": 311, + "featureName": "A restock applies once", + "criterion": "311a", + "points": 3, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-056", + "scenario": "scenarios/03-scheduled-restock-apply.json", + "feature": 305, + "featureName": "A due restock applies", + "criterion": "305a", + "points": 3, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-057", + "scenario": "scenarios/03-scheduled-restock-cancel.json", + "feature": 306, + "featureName": "A scheduled restock can be cancelled", + "criterion": "306a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-058", + "scenario": "scenarios/03-scheduled-restocks.json", + "feature": 302, + "featureName": "A restock is pending before it is due", + "criterion": "302a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-059", + "scenario": "scenarios/03-server-time.json", + "feature": 312, + "featureName": "Restart does not run work early", + "criterion": "312a", + "points": 3, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-060", + "scenario": "scenarios/progression-account-state-reconnect.json", + "feature": 105, + "featureName": "An account keeps what belongs to it", + "criterion": "105b", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-061", + "scenario": "scenarios/progression-account-state-reload.json", + "feature": 105, + "featureName": "An account keeps what belongs to it", + "criterion": "105a", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-065", + "scenario": "scenarios/progression-books-balance.json", + "feature": 107, + "featureName": "The books balance", + "criterion": "107a", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-065", + "scenario": "scenarios/progression-books-balance.json", + "feature": 107, + "featureName": "The books balance", + "criterion": "107b", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-068", + "scenario": "scenarios/progression-cart-checkout.json", + "feature": 4, + "featureName": "Account cart and checkout", + "criterion": "4a", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-068", + "scenario": "scenarios/progression-cart-checkout.json", + "feature": 4, + "featureName": "Account cart and checkout", + "criterion": "4d", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-070", + "scenario": "scenarios/progression-catalog-management.json", + "feature": 622, + "featureName": "Catalog management", + "criterion": "622a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-070", + "scenario": "scenarios/progression-catalog-management.json", + "feature": 622, + "featureName": "Catalog management", + "criterion": "622b", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-071", + "scenario": "scenarios/progression-checkout-crash.json", + "feature": 910, + "featureName": "Checkout crash recovery", + "criterion": "910a", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-071", + "scenario": "scenarios/progression-checkout-crash.json", + "feature": 910, + "featureName": "Checkout crash recovery", + "criterion": "910b", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-073", + "scenario": "scenarios/progression-customer-profile.json", + "feature": 620, + "featureName": "Customer profile", + "criterion": "620c", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-073", + "scenario": "scenarios/progression-customer-profile.json", + "feature": 620, + "featureName": "Customer profile", + "criterion": "620a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-073", + "scenario": "scenarios/progression-customer-profile.json", + "feature": 620, + "featureName": "Customer profile", + "criterion": "620b", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-075", + "scenario": "scenarios/progression-faceted-filters.json", + "feature": 401, + "featureName": "Filters compose", + "criterion": "401a", + "points": 3, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: the category-filter control did not become available in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-076", + "scenario": "scenarios/progression-faceted-pagination.json", + "feature": 402, + "featureName": "Pages are stable", + "criterion": "402a", + "points": 3, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: the minimum-price control did not become available in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-077", + "scenario": "scenarios/progression-managed-support-privacy.json", + "feature": 613, + "featureName": "Managed support privacy", + "criterion": "613b", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-078", + "scenario": "scenarios/progression-managed-support-shared.json", + "feature": 613, + "featureName": "Shared managed support case", + "criterion": "613c", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-078", + "scenario": "scenarios/progression-managed-support-shared.json", + "feature": 613, + "featureName": "Shared managed support case", + "criterion": "613a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-079", + "scenario": "scenarios/progression-notification-preferences.json", + "feature": 630, + "featureName": "Account notification preferences", + "criterion": "630c", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-079", + "scenario": "scenarios/progression-notification-preferences.json", + "feature": 630, + "featureName": "Account notification preferences", + "criterion": "630a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-079", + "scenario": "scenarios/progression-notification-preferences.json", + "feature": 630, + "featureName": "Account notification preferences", + "criterion": "630b", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-080", + "scenario": "scenarios/progression-open-list-live.json", + "feature": 902, + "featureName": "An open list stays current", + "criterion": "902a", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-090", + "scenario": "scenarios/progression-promotion-rules.json", + "feature": 620, + "featureName": "Staff-managed promotion rules", + "criterion": "620a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-090", + "scenario": "scenarios/progression-promotion-rules.json", + "feature": 620, + "featureName": "Staff-managed promotion rules", + "criterion": "620b", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-091", + "scenario": "scenarios/progression-purchasing.json", + "feature": 3, + "featureName": "Purchase order history", + "criterion": "3c", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-093", + "scenario": "scenarios/progression-review-access.json", + "feature": 618, + "featureName": "Review access", + "criterion": "618a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-094", + "scenario": "scenarios/progression-review-script.json", + "feature": 9180, + "featureName": "Stored review content", + "criterion": "9180a", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-095", + "scenario": "scenarios/progression-search-ordering.json", + "feature": 402, + "featureName": "Purchases preserve search ordering", + "criterion": "402b", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-096", + "scenario": "scenarios/progression-shipping-accounting.json", + "feature": 202, + "featureName": "Shipping preserves completed purchase accounting", + "criterion": "202e", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-097", + "scenario": "scenarios/progression-signed-out-purchase.json", + "feature": 3, + "featureName": "Buying", + "criterion": "3a", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: the item-card control matching \"Keyboard\" did not appear" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-099", + "scenario": "scenarios/progression-staff-access.json", + "feature": 601, + "featureName": "Staff access", + "criterion": "601a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "failed", + "failureStage": "assertion", + "detail": "none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-099", + "scenario": "scenarios/progression-staff-access.json", + "feature": 601, + "featureName": "Staff access", + "criterion": "601b", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "failed", + "failureStage": "assertion", + "detail": "none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-101", + "scenario": "scenarios/progression-staff-roles.json", + "feature": 621, + "featureName": "Staff roles", + "criterion": "621c", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-101", + "scenario": "scenarios/progression-staff-roles.json", + "feature": 621, + "featureName": "Staff roles", + "criterion": "621a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-101", + "scenario": "scenarios/progression-staff-roles.json", + "feature": 621, + "featureName": "Staff roles", + "criterion": "621b", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-101", + "scenario": "scenarios/progression-staff-roles.json", + "feature": 621, + "featureName": "Staff roles", + "criterion": "621d", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signin-username, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-102", + "scenario": "scenarios/progression-stock-alert-delivery.json", + "feature": 631, + "featureName": "Stock alert delivery", + "criterion": "631c", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-103", + "scenario": "scenarios/progression-stock-alerts.json", + "feature": 631, + "featureName": "Private one-time stock alerts", + "criterion": "631a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-103", + "scenario": "scenarios/progression-stock-alerts.json", + "feature": 631, + "featureName": "Private one-time stock alerts", + "criterion": "631b", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-107", + "scenario": "scenarios/progression-support-history.json", + "feature": 612, + "featureName": "Customer support history", + "criterion": "612c", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-107", + "scenario": "scenarios/progression-support-history.json", + "feature": 612, + "featureName": "Customer support history", + "criterion": "612a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-107", + "scenario": "scenarios/progression-support-history.json", + "feature": 612, + "featureName": "Customer support history", + "criterion": "612b", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-107", + "scenario": "scenarios/progression-support-history.json", + "feature": 612, + "featureName": "Customer support history", + "criterion": "612d", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-108", + "scenario": "scenarios/progression-support-intake.json", + "feature": 610, + "featureName": "Support intake", + "criterion": "610a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "failed", + "failureStage": "assertion", + "detail": "the support-link control did not become available in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-113", + "scenario": "scenarios/progression-support-triage.json", + "feature": 611, + "featureName": "Support triage", + "criterion": "611a", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: the support-link control did not become available in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-113", + "scenario": "scenarios/progression-support-triage.json", + "feature": 611, + "featureName": "Support triage", + "criterion": "611b", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: the support-link control did not become available in time" + }, + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-113", + "scenario": "scenarios/progression-support-triage.json", + "feature": 611, + "featureName": "Support triage", + "criterion": "611c", + "points": 1, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: the support-link control did not become available in time" + } + ] + } +} diff --git a/tools/stack-bench/qualification-evidence/ecommerce-l3-7cd96d01b/postgres-mutation.json b/tools/stack-bench/qualification-evidence/ecommerce-l3-7cd96d01b/postgres-mutation.json new file mode 100644 index 00000000000..bc7c4139e2f --- /dev/null +++ b/tools/stack-bench/qualification-evidence/ecommerce-l3-7cd96d01b/postgres-mutation.json @@ -0,0 +1,955 @@ +{ + "artifactSchemaVersion": 2, + "kind": "reference_qualification", + "id": "reference-live-postgres-20260917222452-31", + "attempt": { + "id": "reference-live-postgres-20260917222452-31", + "parentId": null + }, + "timestamps": { + "startedAt": "2026-09-17T22:24:52.439Z", + "completedAt": "2026-09-17T23:08:14.542Z" + }, + "identities": { + "engine": { + "id": "stack-bench", + "sha256": "ee2e27156ab1080f508abaf810d87c114aba21846768f33897be0581aeb7a795" + }, + "recipe": { + "id": "ecommerce.progression-catalog", + "sha256": "104589b973c1e7dd1a2410659759989eb0de08b16efeda3131777f82858a0a8b" + }, + "fixture": { + "id": "ecommerce-reference-postgres", + "sha256": "f3906fa01050f00a0ed76c69c256a6b0013bbf72eb72c03aa92d79e47b71c2b8" + }, + "calibration": { + "id": "ecommerce.dependency-l3-calibration", + "sha256": "1b0b4927efbcabbaf8975f4ffbb0ebc77d6af2679fc0f9cac9ef492d751933e0" + }, + "experiment": null, + "agentAdapter": null, + "stackAdapter": { + "id": "postgres", + "sha256": null + }, + "packs": [] + }, + "payload": { + "fixture": "ecommerce-reference-postgres", + "fixtureSha256": "f3906fa01050f00a0ed76c69c256a6b0013bbf72eb72c03aa92d79e47b71c2b8", + "requiredRepetitions": 1, + "isolation": "docker", + "runner": { + "schemaVersion": 1, + "mode": "appliance", + "platform": "linux", + "architecture": "x64", + "hostname": "docker-desktop", + "dockerEngineVersion": "29.6.2", + "dockerOs": "linux", + "dockerArchitecture": "x86_64", + "kernelVersion": "6.6.87.2-microsoft-standard-WSL2", + "cpuCount": 32, + "memoryBytes": 49232842752, + "containersRunning": 10, + "packageRegistry": "http://127.0.0.1:4873/" + }, + "qualificationScope": { + "checksSha256": "ce9efe7f66ef111ce68dc65dcb22b48e20e4e89e68bd62fb7f7776e6a379f64d", + "executableSha256": "53b1dcbe4d602e82f17999dc7e49fad71920e5af156e338e3755119e803477dd", + "kind": "mutation", + "mutationSha256": "194ecf8d31ee18c1e78b15e84a6ae92d4fd32f0b759f12755ba0ffab42978562", + "recipe": { + "contentSha256": "104589b973c1e7dd1a2410659759989eb0de08b16efeda3131777f82858a0a8b", + "id": "ecommerce.progression-catalog" + }, + "schemaVersion": 3, + "stack": { + "id": "postgres", + "reference": { + "id": "ecommerce-reference-postgres", + "sourceSha256": "f3906fa01050f00a0ed76c69c256a6b0013bbf72eb72c03aa92d79e47b71c2b8" + }, + "version": "1.6.0" + }, + "sha256": "456fa299ca4edf2fb5affbe1dc852c854bb5ccc1b01e5c019c62b7eb6788345a" + }, + "mutationControl": true, + "runs": [ + { + "repetition": 1, + "output": "ecommerce-l3-104589b973c1-postgres-mutation.runs/r1-workers", + "durationMs": 2601986, + "processError": null, + "harnessSha256Before": "c911977ee8f6b0894c581b7c9d95957441c8052f7404e7ebff17f00cec4d86e5", + "harnessSha256After": "c911977ee8f6b0894c581b7c9d95957441c8052f7404e7ebff17f00cec4d86e5", + "ok": true, + "failures": [], + "runId": "reference-live-postgres-20260917222452-31", + "score": "183/183", + "imageId": "sha256:32ff9a9e519ba9d1af2fe72f24622caa8ca7a9f2baf2338c6b1e0435e6ac5455", + "criteria": 114, + "zeroPointCriteria": 0, + "fingerprint": "3197a361efd9c27179e97087a9e9e342476520f9b1ae1fef4e358b08893058a8", + "outcome": "passed", + "packRuntime": { + "schemaVersion": 1, + "metric": "pack-check-wall-clock-sum-v1", + "packs": [ + { + "id": "ecommerce.feature.accounts", + "checkCount": 4, + "setupRuntimeMs": 1019, + "criterionRuntimeMs": 15352, + "measuredRuntimeMs": 16371, + "budget": { + "status": "bounded", + "maxRuntimeMs": 18000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.cart", + "checkCount": 1, + "setupRuntimeMs": 497, + "criterionRuntimeMs": 6057, + "measuredRuntimeMs": 6554, + "budget": { + "status": "bounded", + "maxRuntimeMs": 42000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.catalog-discovery", + "checkCount": 2, + "setupRuntimeMs": 1, + "criterionRuntimeMs": 1976, + "measuredRuntimeMs": 1977, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.catalog-items", + "checkCount": 1, + "setupRuntimeMs": 0, + "criterionRuntimeMs": 227, + "measuredRuntimeMs": 227, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.checkout", + "checkCount": 1, + "setupRuntimeMs": 497, + "criterionRuntimeMs": 6013, + "measuredRuntimeMs": 6510, + "budget": { + "status": "bounded", + "maxRuntimeMs": 42000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.purchasing", + "checkCount": 1, + "setupRuntimeMs": 331, + "criterionRuntimeMs": 1180, + "measuredRuntimeMs": 1511, + "budget": { + "status": "bounded", + "maxRuntimeMs": 24000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.reviews", + "checkCount": 1, + "setupRuntimeMs": 1732, + "criterionRuntimeMs": 432, + "measuredRuntimeMs": 2164, + "budget": { + "status": "bounded", + "maxRuntimeMs": 22000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.warehouse-admin", + "checkCount": 2, + "setupRuntimeMs": 1344, + "criterionRuntimeMs": 4349, + "measuredRuntimeMs": 5693, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.inventory-dashboard", + "checkCount": 1, + "setupRuntimeMs": 3548, + "criterionRuntimeMs": 9, + "measuredRuntimeMs": 3557, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.order-cancellation-features", + "checkCount": 2, + "setupRuntimeMs": 1075, + "criterionRuntimeMs": 11260, + "measuredRuntimeMs": 12335, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.recommendations", + "checkCount": 1, + "setupRuntimeMs": 338, + "criterionRuntimeMs": 5177, + "measuredRuntimeMs": 5515, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.sales-dashboard", + "checkCount": 2, + "setupRuntimeMs": 2055, + "criterionRuntimeMs": 5062, + "measuredRuntimeMs": 7117, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.stock-transfers-features", + "checkCount": 1, + "setupRuntimeMs": 533, + "criterionRuntimeMs": 1057, + "measuredRuntimeMs": 1590, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.deferred-access-specifications", + "checkCount": 1, + "setupRuntimeMs": 20929, + "criterionRuntimeMs": 4291, + "measuredRuntimeMs": 25220, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.deferred-durability-specifications", + "checkCount": 1, + "setupRuntimeMs": 126364, + "criterionRuntimeMs": 41064, + "measuredRuntimeMs": 167428, + "budget": { + "status": "bounded", + "maxRuntimeMs": 720000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.deferred-integrity-specifications", + "checkCount": 1, + "setupRuntimeMs": 42261, + "criterionRuntimeMs": 38490, + "measuredRuntimeMs": 80751, + "budget": { + "status": "bounded", + "maxRuntimeMs": 400000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.scheduled-restocks-features", + "checkCount": 3, + "setupRuntimeMs": 61539, + "criterionRuntimeMs": 70376, + "measuredRuntimeMs": 131915, + "budget": { + "status": "bounded", + "maxRuntimeMs": 150000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.server-time-specifications", + "checkCount": 1, + "setupRuntimeMs": 27295, + "criterionRuntimeMs": 112908, + "measuredRuntimeMs": 140203, + "budget": { + "status": "bounded", + "maxRuntimeMs": 300000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.cancellation-accounting-specifications", + "checkCount": 1, + "setupRuntimeMs": 936, + "criterionRuntimeMs": 9579, + "measuredRuntimeMs": 10515, + "budget": { + "status": "bounded", + "maxRuntimeMs": 24000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.catalog-management", + "checkCount": 2, + "setupRuntimeMs": 3407, + "criterionRuntimeMs": 22, + "measuredRuntimeMs": 3429, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.customer-profile", + "checkCount": 1, + "setupRuntimeMs": 527, + "criterionRuntimeMs": 5072, + "measuredRuntimeMs": 5599, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.faceted-search", + "checkCount": 2, + "setupRuntimeMs": 42702, + "criterionRuntimeMs": 25568, + "measuredRuntimeMs": 68270, + "budget": { + "status": "bounded", + "maxRuntimeMs": 141000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.fulfilment-queue", + "checkCount": 2, + "setupRuntimeMs": 1272, + "criterionRuntimeMs": 26980, + "measuredRuntimeMs": 28252, + "budget": { + "status": "bounded", + "maxRuntimeMs": 76000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.inventory-conservation-specifications", + "checkCount": 5, + "setupRuntimeMs": 2700, + "criterionRuntimeMs": 45224, + "measuredRuntimeMs": 47924, + "budget": { + "status": "bounded", + "maxRuntimeMs": 138000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.managed-support", + "checkCount": 1, + "setupRuntimeMs": 1105, + "criterionRuntimeMs": 6204, + "measuredRuntimeMs": 7309, + "budget": { + "status": "bounded", + "maxRuntimeMs": 55000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.notification-preferences", + "checkCount": 1, + "setupRuntimeMs": 677, + "criterionRuntimeMs": 5073, + "measuredRuntimeMs": 5750, + "budget": { + "status": "bounded", + "maxRuntimeMs": 40000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.operations-access-specifications", + "checkCount": 3, + "setupRuntimeMs": 10011, + "criterionRuntimeMs": 34156, + "measuredRuntimeMs": 44167, + "budget": { + "status": "bounded", + "maxRuntimeMs": 98000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.promotion-rules", + "checkCount": 1, + "setupRuntimeMs": 589, + "criterionRuntimeMs": 375, + "measuredRuntimeMs": 964, + "budget": { + "status": "bounded", + "maxRuntimeMs": 45000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.review-access-specifications", + "checkCount": 2, + "setupRuntimeMs": 8895, + "criterionRuntimeMs": 9541, + "measuredRuntimeMs": 18436, + "budget": { + "status": "bounded", + "maxRuntimeMs": 82000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.staff-access", + "checkCount": 1, + "setupRuntimeMs": 0, + "criterionRuntimeMs": 782, + "measuredRuntimeMs": 782, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.staff-roles", + "checkCount": 1, + "setupRuntimeMs": 772, + "criterionRuntimeMs": 26, + "measuredRuntimeMs": 798, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.stock-alerts", + "checkCount": 1, + "setupRuntimeMs": 3943, + "criterionRuntimeMs": 11163, + "measuredRuntimeMs": 15106, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.support-history", + "checkCount": 1, + "setupRuntimeMs": 859, + "criterionRuntimeMs": 1135, + "measuredRuntimeMs": 1994, + "budget": { + "status": "bounded", + "maxRuntimeMs": 50000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.support-intake", + "checkCount": 1, + "setupRuntimeMs": 0, + "criterionRuntimeMs": 441, + "measuredRuntimeMs": 441, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.support-triage", + "checkCount": 3, + "setupRuntimeMs": 927, + "criterionRuntimeMs": 10071, + "measuredRuntimeMs": 10998, + "budget": { + "status": "bounded", + "maxRuntimeMs": 45000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.access-control", + "checkCount": 21, + "setupRuntimeMs": 27625, + "criterionRuntimeMs": 212621, + "measuredRuntimeMs": 240246, + "budget": { + "status": "bounded", + "maxRuntimeMs": 464000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.concurrency-safety", + "checkCount": 6, + "setupRuntimeMs": 24565, + "criterionRuntimeMs": 58044, + "measuredRuntimeMs": 82609, + "budget": { + "status": "bounded", + "maxRuntimeMs": 125000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.external-data-sync", + "checkCount": 3, + "setupRuntimeMs": 670, + "criterionRuntimeMs": 28234, + "measuredRuntimeMs": 28904, + "budget": { + "status": "bounded", + "maxRuntimeMs": 105000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.live-state", + "checkCount": 11, + "setupRuntimeMs": 20495, + "criterionRuntimeMs": 6782, + "measuredRuntimeMs": 27277, + "budget": { + "status": "bounded", + "maxRuntimeMs": 184000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.search-ordering", + "checkCount": 1, + "setupRuntimeMs": 20800, + "criterionRuntimeMs": 5194, + "measuredRuntimeMs": 25994, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.state-durability", + "checkCount": 10, + "setupRuntimeMs": 11999, + "criterionRuntimeMs": 64392, + "measuredRuntimeMs": 76391, + "budget": { + "status": "bounded", + "maxRuntimeMs": 768000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.transactional-integrity", + "checkCount": 6, + "setupRuntimeMs": 24082, + "criterionRuntimeMs": 30891, + "measuredRuntimeMs": 54973, + "budget": { + "status": "bounded", + "maxRuntimeMs": 100000 + }, + "exceeded": false + } + ] + }, + "mutations": { + "caught": 114, + "total": 114 + }, + "baselineDurationMs": 1929224, + "baselineOutput": "ecommerce-l3-104589b973c1-postgres-mutation.runs/r1", + "baselineHarnessSha256Before": "c911977ee8f6b0894c581b7c9d95957441c8052f7404e7ebff17f00cec4d86e5", + "baselineHarnessSha256After": "c911977ee8f6b0894c581b7c9d95957441c8052f7404e7ebff17f00cec4d86e5", + "workers": [ + { + "index": 0, + "runIndex": 0, + "artifact": "ecommerce-l3-104589b973c1-postgres-mutation.runs/r1-workers/w1.json", + "mutationIds": [ + "staff-admin-access-survives-role-removal", + "signed-out-purchase-uses-default-account", + "unauthenticated-direct-purchase-uses-default-account", + "cart-update-accepts-negative-quantity", + "cancel-does-not-restore-stock-feature", + "transfer-debits-source-without-crediting-existing-destination", + "progression-customer-sees-staff-tools", + "progression-support-history-is-not-persisted", + "stock-alert-delivery-is-suppressed", + "progression-cancelled-restock-still-runs", + "progression-cancelled-orders-remain-in-revenue", + "progression-staff-can-restock-directly", + "support-history-rows-are-hidden", + "purchase-does-not-broadcast-fulfilment-queue", + "review-script-unsafe-render" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-104589b973c1-postgres-mutation.runs/r1-workers/w1.stdout.log", + "stderr": "ecommerce-l3-104589b973c1-postgres-mutation.runs/r1-workers/w1.stderr.log" + } + }, + { + "index": 1, + "runIndex": 1, + "artifact": "ecommerce-l3-104589b973c1-postgres-mutation.runs/r1-workers/w2.json", + "mutationIds": [ + "shipping-counts-sale-twice", + "purchase-stock-change-is-not-broadcast--01-buying", + "direct-purchase-is-attributed-to-previous-account", + "oversell-no-row-lock", + "cancellation-accounting-loses-stock-restoration", + "recommendations-ignore-pending-purchases", + "progression-staff-role-is-lost-on-restart", + "progression-support-history-leaks", + "stock-alert-is-sent-after-every-restock", + "progression-restart-timer-never-runs", + "progression-shipping-keeps-order-pending", + "progression-restock-adds-wrong-quantity", + "authorized-restock-does-not-change-stock", + "admin-state-change-is-not-broadcast", + "review-script-reject-all" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-104589b973c1-postgres-mutation.runs/r1-workers/w2.stdout.log", + "stderr": "ecommerce-l3-104589b973c1-postgres-mutation.runs/r1-workers/w2.stderr.log" + } + }, + { + "index": 2, + "runIndex": 2, + "artifact": "ecommerce-l3-104589b973c1-postgres-mutation.runs/r1-workers/w3.json", + "mutationIds": [ + "signup-ui-does-not-enter-created-account", + "restock-race-records-wrong-order-total", + "direct-purchase-uses-constant-price", + "purchase-read-write-loses-concurrent-stock", + "cancel-does-not-restore-stock-fresh-client", + "purchases-do-not-affect-best-sellers", + "staff-role-write-precedes-denial", + "progression-managed-support-is-not-shared", + "progression-stock-alerts-leak-across-accounts", + "progression-cart-line-does-not-increment", + "progression-concurrent-cart-line-does-not-increment", + "progression-cart-add-uses-another-account", + "low-stock-threshold-is-two-units", + "admin-sockets-do-not-join-admin-room" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-104589b973c1-postgres-mutation.runs/r1-workers/w3.stdout.log", + "stderr": "ecommerce-l3-104589b973c1-postgres-mutation.runs/r1-workers/w3.stderr.log" + } + }, + { + "index": 3, + "runIndex": 3, + "artifact": "ecommerce-l3-104589b973c1-postgres-mutation.runs/r1-workers/w4.json", + "mutationIds": [ + "duplicate-signup-authenticates-existing-account", + "direct-purchase-order-total-is-offset", + "account-state-reload-discards-session", + "external-stock-polling-disabled", + "cancel-restores-stock-but-keeps-pending-status", + "queue-warehouse-reports-west", + "progression-staff-can-assign-roles", + "progression-managed-support-leaks", + "progression-faceted-filter-ignores-category", + "progression-checkout-leaves-cart-lines", + "progression-concurrent-checkout-leaves-cart-lines", + "progression-customers-can-manage-scheduled-work", + "category-totals-render-as-session-deltas", + "transfer-overdraft-guard-skips-bulk-transfers" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-104589b973c1-postgres-mutation.runs/r1-workers/w4.stdout.log", + "stderr": "ecommerce-l3-104589b973c1-postgres-mutation.runs/r1-workers/w4.stderr.log" + } + }, + { + "index": 4, + "runIndex": 4, + "artifact": "ecommerce-l3-104589b973c1-postgres-mutation.runs/r1-workers/w5.json", + "mutationIds": [ + "password-verification-is-inverted", + "reload-hydrates-an-empty-cart", + "offline-event-clears-account-state", + "server-restart-does-not-resynchronize-catalog", + "operator-authorization-allows-customer-transfer", + "transfer-overwrites-concurrent-purchase-with-stale-stock", + "progression-catalog-product-name-is-not-published", + "progression-promotion-discount-is-offset", + "active-search-uses-purchase-ranking", + "progression-cart-update-uses-wrong-room", + "progression-catalog-ranking-is-reversed", + "progression-restock-does-not-survive-restart", + "profile-summary-ignores-saved-address", + "transfer-does-not-publish-warehouse-totals" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-104589b973c1-postgres-mutation.runs/r1-workers/w5.stdout.log", + "stderr": "ecommerce-l3-104589b973c1-postgres-mutation.runs/r1-workers/w5.stderr.log" + } + }, + { + "index": 5, + "runIndex": 5, + "artifact": "ecommerce-l3-104589b973c1-postgres-mutation.runs/r1-workers/w6.json", + "mutationIds": [ + "correct-signin-is-refused", + "signed-out-visitors-do-not-see-reviews", + "purchase-does-not-decrement-warehouse-stock", + "reconnect-does-not-send-current-catalog", + "customer-can-ship-order-direct-1-1", + "progression-profile-address-is-discarded", + "progression-catalog-variants-are-discarded", + "progression-customer-can-create-promotions", + "progression-pagination-always-shows-first-page", + "progression-order-history-ignores-owner", + "progression-catalog-search-requires-exact-name", + "progression-restock-can-apply-more-than-once", + "support-first-reply-is-hidden", + "progression-support-history-anonymous-leak" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-104589b973c1-postgres-mutation.runs/r1-workers/w6.stdout.log", + "stderr": "ecommerce-l3-104589b973c1-postgres-mutation.runs/r1-workers/w6.stderr.log" + } + }, + { + "index": 6, + "runIndex": 6, + "artifact": "ecommerce-l3-104589b973c1-postgres-mutation.runs/r1-workers/w7.json", + "mutationIds": [ + "reload-discards-session-identity", + "review-average-update-is-not-broadcast", + "review-route-skips-purchase-eligibility", + "open-review-list-ignores-live-update", + "customer-can-cancel-foreign-order-1-1", + "progression-profile-reads-another-account", + "progression-support-intake-is-disabled", + "progression-notification-preferences-do-not-save", + "progression-restock-countdown-is-fixed", + "progression-review-conflict-is-not-updated", + "progression-catalog-price-is-offset", + "restock-overwrites-instead-of-increments", + "notification-sync-flips-saved-toggle", + "checkout-crash-integrity" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-104589b973c1-postgres-mutation.runs/r1-workers/w7.stdout.log", + "stderr": "ecommerce-l3-104589b973c1-postgres-mutation.runs/r1-workers/w7.stderr.log" + } + }, + { + "index": 7, + "runIndex": 7, + "artifact": "ecommerce-l3-104589b973c1-postgres-mutation.runs/r1-workers/w8.json", + "mutationIds": [ + "purchase-does-not-broadcast-ranking", + "admin-warehouse-view-drops-one-location", + "only-shipped-orders-earn-review-eligibility", + "open-review-list-renders-each-review-twice", + "progression-customer-sees-fulfilment-content", + "progression-staff-tools-are-hidden", + "progression-support-triage-update-is-disabled", + "progression-notifications-leak-across-accounts", + "progression-due-restock-does-not-run", + "progression-revenue-double-counts-orders", + "progression-staff-sees-admin-navigation", + "direct-review-access-is-not-checked", + "staff-role-form-reverts-after-save", + "checkout-crash-durability" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-104589b973c1-postgres-mutation.runs/r1-workers/w8.stdout.log", + "stderr": "ecommerce-l3-104589b973c1-postgres-mutation.runs/r1-workers/w8.stderr.log" + } + } + ] + } + ], + "stable": true, + "sameImage": true, + "sameHarness": true, + "harnessSha256": "c911977ee8f6b0894c581b7c9d95957441c8052f7404e7ebff17f00cec4d86e5", + "qualifiedCheckKeys": [ + "ecommerce.feature.accounts.accounts.1a", + "ecommerce.feature.accounts.accounts.1b", + "ecommerce.feature.accounts.accounts.1c", + "ecommerce.feature.accounts.accounts.1d", + "ecommerce.feature.cart-checkout.cart.4a", + "ecommerce.feature.cart-checkout.cart.4d", + "ecommerce.feature.catalog.catalog-ranking.2b", + "ecommerce.feature.catalog.catalog-search.2d", + "ecommerce.feature.catalog.catalog-values.2a", + "ecommerce.feature.purchasing.purchase-order.3c", + "ecommerce.feature.reviews.reviews.6a", + "ecommerce.feature.warehouse-admin.admin-write.103a", + "ecommerce.feature.warehouse-admin.warehouse-view.7b", + "ecommerce.inventory-operations.operational-views.5c", + "ecommerce.inventory-operations.operational-views.5d", + "ecommerce.inventory-operations.operational-views.5e", + "ecommerce.inventory-operations.operational-views.5f", + "ecommerce.inventory-operations.shipping-accounting.202e", + "ecommerce.inventory-operations.stock-conservation.202a", + "ecommerce.inventory-operations.stock-conservation.202b", + "ecommerce.inventory-operations.stock-conservation.202c", + "ecommerce.inventory-operations.stock-conservation.202d", + "ecommerce.inventory-operations.warehouse-transfer.2a", + "ecommerce.l3.deferred-access.scheduled-work-access.317a", + "ecommerce.l3.deferred-durability.restart-survival.311a", + "ecommerce.l3.deferred-integrity.exactly-once.311a", + "ecommerce.l3.scheduled-restocks.scheduled-restocks.302a", + "ecommerce.l3.scheduled-restocks.scheduled-restocks.305a", + "ecommerce.l3.scheduled-restocks.scheduled-restocks.306a", + "ecommerce.l3.server-time.server-time.312a", + "ecommerce.operations-access.fulfilment-queue.1b", + "ecommerce.operations-access.fulfilment-queue.1c", + "ecommerce.operations-access.operator-authorization.201a", + "ecommerce.operations-access.operator-authorization.201c", + "ecommerce.operations-access.order-owner.204a", + "ecommerce.progression.catalog-management.catalog-management.622a", + "ecommerce.progression.catalog-management.catalog-management.622b", + "ecommerce.progression.customer-profile.customer-profile.620c", + "ecommerce.progression.faceted-search.faceted-search.401a", + "ecommerce.progression.faceted-search.faceted-search.402a", + "ecommerce.progression.managed-support.managed-support.613c", + "ecommerce.progression.notification-preferences.notification-preferences.630c", + "ecommerce.progression.promotion-rules.promotion-rule-values.620a", + "ecommerce.progression.review-access-specifications.review-eligibility-direct.618a", + "ecommerce.progression.review-access-specifications.stored-review-script.9180a", + "ecommerce.progression.staff-access.staff-access.601a", + "ecommerce.progression.staff-roles.staff-roles.621c", + "ecommerce.progression.stock-alerts.stock-alert-delivery.631c", + "ecommerce.progression.support-history.support-history.612c", + "ecommerce.progression.support-intake.support-intake.610a", + "ecommerce.progression.support-triage.support-assignment.611a", + "ecommerce.progression.support-triage.support-priority.611b", + "ecommerce.progression.support-triage.support-status.611c", + "ecommerce.returns-pricing.cancellation-and-return.3a", + "ecommerce.returns-pricing.cancellation-and-return.3b", + "ecommerce.returns-pricing.refund-accounting.203a", + "ecommerce.spec.access-control.cart-boundary.109a", + "ecommerce.spec.access-control.cart-boundary.109b", + "ecommerce.spec.access-control.customer-profile-privacy.620b", + "ecommerce.spec.access-control.fulfilment-area-boundary.1d", + "ecommerce.spec.access-control.managed-support-privacy.613b", + "ecommerce.spec.access-control.notification-preferences-privacy.630b", + "ecommerce.spec.access-control.order-ownership.106a", + "ecommerce.spec.access-control.promotion-management-boundary.620b", + "ecommerce.spec.access-control.purchase-attribution.102a", + "ecommerce.spec.access-control.purchase-session.101a", + "ecommerce.spec.access-control.review-eligibility.108a", + "ecommerce.spec.access-control.review-eligibility.108b", + "ecommerce.spec.access-control.signed-out-purchase.3a", + "ecommerce.spec.access-control.staff-area-boundary.601b", + "ecommerce.spec.access-control.staff-role-boundary.621b", + "ecommerce.spec.access-control.staff-role-revocation.621d", + "ecommerce.spec.access-control.stock-alert-privacy.631b", + "ecommerce.spec.access-control.support-history-logout.612d", + "ecommerce.spec.access-control.support-history-privacy.612b", + "ecommerce.spec.access-control.warehouse-area-boundary.7a", + "ecommerce.spec.access-control.warehouse-write-boundary.103b", + "ecommerce.spec.concurrency-safety.duplicate-checkout.203a", + "ecommerce.spec.concurrency-safety.duplicate-checkout.203b", + "ecommerce.spec.concurrency-safety.last-unit.201a", + "ecommerce.spec.concurrency-safety.last-unit.201b", + "ecommerce.spec.concurrency-safety.last-unit.201c", + "ecommerce.spec.concurrency-safety.restock-race.202a", + "ecommerce.spec.external-data-sync.external-stock.901a", + "ecommerce.spec.external-data-sync.external-stock.901c", + "ecommerce.spec.external-data-sync.external-stock.901d", + "ecommerce.spec.live-state.fulfilment-queue.1a", + "ecommerce.spec.live-state.inventory-dashboard.5a", + "ecommerce.spec.live-state.managed-support.613a", + "ecommerce.spec.live-state.open-list.902a", + "ecommerce.spec.live-state.purchase-stock.3b", + "ecommerce.spec.live-state.ranking.2c", + "ecommerce.spec.live-state.rating.6c", + "ecommerce.spec.live-state.sales-dashboard.5b", + "ecommerce.spec.live-state.shared-cart.4c", + "ecommerce.spec.live-state.stock-transfers.2b", + "ecommerce.spec.live-state.warehouse-stock.7c", + "ecommerce.spec.search-ordering.search-ordering.402b", + "ecommerce.spec.state-durability.account-state-recovery.105a", + "ecommerce.spec.state-durability.account-state-recovery.105b", + "ecommerce.spec.state-durability.cart-reload.4b", + "ecommerce.spec.state-durability.checkout-crash-durability.910b", + "ecommerce.spec.state-durability.checkout-crash-integrity.910a", + "ecommerce.spec.state-durability.customer-profile-reload.620a", + "ecommerce.spec.state-durability.notification-preferences-reload.630a", + "ecommerce.spec.state-durability.session-reload.1e", + "ecommerce.spec.state-durability.staff-role-reload.621a", + "ecommerce.spec.state-durability.support-history-reload.612a", + "ecommerce.spec.transactional-integrity.books-balance.107a", + "ecommerce.spec.transactional-integrity.books-balance.107b", + "ecommerce.spec.transactional-integrity.server-price.104a", + "ecommerce.spec.transactional-integrity.stock-alert-deduplication.631a", + "ecommerce.spec.transactional-integrity.stock-transfer-overdraw.2c", + "ecommerce.spec.transactional-integrity.unique-review.6b" + ], + "featureCatalog": { + "contentSha256": "8671f7883c2e5a24474a546ef1517407cd9334258e1a7cfe91e292a9af1952f2", + "id": "ecommerce.questlines" + }, + "diagnostic": false, + "ok": true + } +} diff --git a/tools/stack-bench/qualification-evidence/ecommerce-l3-7cd96d01b/postgres-reference.json b/tools/stack-bench/qualification-evidence/ecommerce-l3-7cd96d01b/postgres-reference.json new file mode 100644 index 00000000000..6cae5296064 --- /dev/null +++ b/tools/stack-bench/qualification-evidence/ecommerce-l3-7cd96d01b/postgres-reference.json @@ -0,0 +1,736 @@ +{ + "artifactSchemaVersion": 2, + "kind": "reference_qualification", + "id": "reference-live-postgres-20260917222452-31-reference", + "attempt": { + "id": "reference-live-postgres-20260917222452-31-reference", + "parentId": null + }, + "timestamps": { + "startedAt": "2026-09-17T22:24:52.439Z", + "completedAt": "2026-09-17T23:08:14.543Z" + }, + "identities": { + "engine": { + "id": "stack-bench", + "sha256": "ee2e27156ab1080f508abaf810d87c114aba21846768f33897be0581aeb7a795" + }, + "recipe": { + "id": "ecommerce.progression-catalog", + "sha256": "104589b973c1e7dd1a2410659759989eb0de08b16efeda3131777f82858a0a8b" + }, + "fixture": { + "id": "ecommerce-reference-postgres", + "sha256": "f3906fa01050f00a0ed76c69c256a6b0013bbf72eb72c03aa92d79e47b71c2b8" + }, + "calibration": { + "id": "ecommerce.dependency-l3-calibration", + "sha256": "1b0b4927efbcabbaf8975f4ffbb0ebc77d6af2679fc0f9cac9ef492d751933e0" + }, + "experiment": null, + "agentAdapter": null, + "stackAdapter": { + "id": "postgres", + "sha256": null + }, + "packs": [] + }, + "payload": { + "fixture": "ecommerce-reference-postgres", + "fixtureSha256": "f3906fa01050f00a0ed76c69c256a6b0013bbf72eb72c03aa92d79e47b71c2b8", + "requiredRepetitions": 1, + "isolation": "docker", + "runner": { + "schemaVersion": 1, + "mode": "appliance", + "platform": "linux", + "architecture": "x64", + "hostname": "docker-desktop", + "dockerEngineVersion": "29.6.2", + "dockerOs": "linux", + "dockerArchitecture": "x86_64", + "kernelVersion": "6.6.87.2-microsoft-standard-WSL2", + "cpuCount": 32, + "memoryBytes": 49232842752, + "containersRunning": 10, + "packageRegistry": "http://127.0.0.1:4873/" + }, + "qualificationScope": { + "checksSha256": "ce9efe7f66ef111ce68dc65dcb22b48e20e4e89e68bd62fb7f7776e6a379f64d", + "executableSha256": "53b1dcbe4d602e82f17999dc7e49fad71920e5af156e338e3755119e803477dd", + "kind": "reference", + "mutationSha256": null, + "recipe": { + "contentSha256": "104589b973c1e7dd1a2410659759989eb0de08b16efeda3131777f82858a0a8b", + "id": "ecommerce.progression-catalog" + }, + "schemaVersion": 3, + "stack": { + "id": "postgres", + "reference": { + "id": "ecommerce-reference-postgres", + "sourceSha256": "f3906fa01050f00a0ed76c69c256a6b0013bbf72eb72c03aa92d79e47b71c2b8" + }, + "version": "1.6.0" + }, + "sha256": "afbc23eddb27870d42bb3be22461b6dc8796a0f9e57e858a32ec9da7bd19accc" + }, + "mutationControl": false, + "runs": [ + { + "repetition": 1, + "output": "ecommerce-l3-104589b973c1-postgres-mutation.runs/r1", + "durationMs": 1929224, + "processError": null, + "harnessSha256Before": "c911977ee8f6b0894c581b7c9d95957441c8052f7404e7ebff17f00cec4d86e5", + "harnessSha256After": "c911977ee8f6b0894c581b7c9d95957441c8052f7404e7ebff17f00cec4d86e5", + "ok": true, + "failures": [], + "runId": "ecommerce-postgres-run0-20260917222453-256bef47", + "score": "183/183", + "imageId": "sha256:32ff9a9e519ba9d1af2fe72f24622caa8ca7a9f2baf2338c6b1e0435e6ac5455", + "criteria": 114, + "zeroPointCriteria": 0, + "fingerprint": "3197a361efd9c27179e97087a9e9e342476520f9b1ae1fef4e358b08893058a8", + "outcome": "passed", + "packRuntime": { + "schemaVersion": 1, + "metric": "pack-check-wall-clock-sum-v1", + "packs": [ + { + "id": "ecommerce.feature.accounts", + "checkCount": 4, + "setupRuntimeMs": 1019, + "criterionRuntimeMs": 15352, + "measuredRuntimeMs": 16371, + "budget": { + "status": "bounded", + "maxRuntimeMs": 18000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.cart", + "checkCount": 1, + "setupRuntimeMs": 497, + "criterionRuntimeMs": 6057, + "measuredRuntimeMs": 6554, + "budget": { + "status": "bounded", + "maxRuntimeMs": 42000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.catalog-discovery", + "checkCount": 2, + "setupRuntimeMs": 1, + "criterionRuntimeMs": 1976, + "measuredRuntimeMs": 1977, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.catalog-items", + "checkCount": 1, + "setupRuntimeMs": 0, + "criterionRuntimeMs": 227, + "measuredRuntimeMs": 227, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.checkout", + "checkCount": 1, + "setupRuntimeMs": 497, + "criterionRuntimeMs": 6013, + "measuredRuntimeMs": 6510, + "budget": { + "status": "bounded", + "maxRuntimeMs": 42000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.purchasing", + "checkCount": 1, + "setupRuntimeMs": 331, + "criterionRuntimeMs": 1180, + "measuredRuntimeMs": 1511, + "budget": { + "status": "bounded", + "maxRuntimeMs": 24000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.reviews", + "checkCount": 1, + "setupRuntimeMs": 1732, + "criterionRuntimeMs": 432, + "measuredRuntimeMs": 2164, + "budget": { + "status": "bounded", + "maxRuntimeMs": 22000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.warehouse-admin", + "checkCount": 2, + "setupRuntimeMs": 1344, + "criterionRuntimeMs": 4349, + "measuredRuntimeMs": 5693, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.inventory-dashboard", + "checkCount": 1, + "setupRuntimeMs": 3548, + "criterionRuntimeMs": 9, + "measuredRuntimeMs": 3557, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.order-cancellation-features", + "checkCount": 2, + "setupRuntimeMs": 1075, + "criterionRuntimeMs": 11260, + "measuredRuntimeMs": 12335, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.recommendations", + "checkCount": 1, + "setupRuntimeMs": 338, + "criterionRuntimeMs": 5177, + "measuredRuntimeMs": 5515, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.sales-dashboard", + "checkCount": 2, + "setupRuntimeMs": 2055, + "criterionRuntimeMs": 5062, + "measuredRuntimeMs": 7117, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.stock-transfers-features", + "checkCount": 1, + "setupRuntimeMs": 533, + "criterionRuntimeMs": 1057, + "measuredRuntimeMs": 1590, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.deferred-access-specifications", + "checkCount": 1, + "setupRuntimeMs": 20929, + "criterionRuntimeMs": 4291, + "measuredRuntimeMs": 25220, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.deferred-durability-specifications", + "checkCount": 1, + "setupRuntimeMs": 126364, + "criterionRuntimeMs": 41064, + "measuredRuntimeMs": 167428, + "budget": { + "status": "bounded", + "maxRuntimeMs": 720000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.deferred-integrity-specifications", + "checkCount": 1, + "setupRuntimeMs": 42261, + "criterionRuntimeMs": 38490, + "measuredRuntimeMs": 80751, + "budget": { + "status": "bounded", + "maxRuntimeMs": 400000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.scheduled-restocks-features", + "checkCount": 3, + "setupRuntimeMs": 61539, + "criterionRuntimeMs": 70376, + "measuredRuntimeMs": 131915, + "budget": { + "status": "bounded", + "maxRuntimeMs": 150000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.server-time-specifications", + "checkCount": 1, + "setupRuntimeMs": 27295, + "criterionRuntimeMs": 112908, + "measuredRuntimeMs": 140203, + "budget": { + "status": "bounded", + "maxRuntimeMs": 300000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.cancellation-accounting-specifications", + "checkCount": 1, + "setupRuntimeMs": 936, + "criterionRuntimeMs": 9579, + "measuredRuntimeMs": 10515, + "budget": { + "status": "bounded", + "maxRuntimeMs": 24000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.catalog-management", + "checkCount": 2, + "setupRuntimeMs": 3407, + "criterionRuntimeMs": 22, + "measuredRuntimeMs": 3429, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.customer-profile", + "checkCount": 1, + "setupRuntimeMs": 527, + "criterionRuntimeMs": 5072, + "measuredRuntimeMs": 5599, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.faceted-search", + "checkCount": 2, + "setupRuntimeMs": 42702, + "criterionRuntimeMs": 25568, + "measuredRuntimeMs": 68270, + "budget": { + "status": "bounded", + "maxRuntimeMs": 141000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.fulfilment-queue", + "checkCount": 2, + "setupRuntimeMs": 1272, + "criterionRuntimeMs": 26980, + "measuredRuntimeMs": 28252, + "budget": { + "status": "bounded", + "maxRuntimeMs": 76000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.inventory-conservation-specifications", + "checkCount": 5, + "setupRuntimeMs": 2700, + "criterionRuntimeMs": 45224, + "measuredRuntimeMs": 47924, + "budget": { + "status": "bounded", + "maxRuntimeMs": 138000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.managed-support", + "checkCount": 1, + "setupRuntimeMs": 1105, + "criterionRuntimeMs": 6204, + "measuredRuntimeMs": 7309, + "budget": { + "status": "bounded", + "maxRuntimeMs": 55000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.notification-preferences", + "checkCount": 1, + "setupRuntimeMs": 677, + "criterionRuntimeMs": 5073, + "measuredRuntimeMs": 5750, + "budget": { + "status": "bounded", + "maxRuntimeMs": 40000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.operations-access-specifications", + "checkCount": 3, + "setupRuntimeMs": 10011, + "criterionRuntimeMs": 34156, + "measuredRuntimeMs": 44167, + "budget": { + "status": "bounded", + "maxRuntimeMs": 98000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.promotion-rules", + "checkCount": 1, + "setupRuntimeMs": 589, + "criterionRuntimeMs": 375, + "measuredRuntimeMs": 964, + "budget": { + "status": "bounded", + "maxRuntimeMs": 45000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.review-access-specifications", + "checkCount": 2, + "setupRuntimeMs": 8895, + "criterionRuntimeMs": 9541, + "measuredRuntimeMs": 18436, + "budget": { + "status": "bounded", + "maxRuntimeMs": 82000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.staff-access", + "checkCount": 1, + "setupRuntimeMs": 0, + "criterionRuntimeMs": 782, + "measuredRuntimeMs": 782, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.staff-roles", + "checkCount": 1, + "setupRuntimeMs": 772, + "criterionRuntimeMs": 26, + "measuredRuntimeMs": 798, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.stock-alerts", + "checkCount": 1, + "setupRuntimeMs": 3943, + "criterionRuntimeMs": 11163, + "measuredRuntimeMs": 15106, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.support-history", + "checkCount": 1, + "setupRuntimeMs": 859, + "criterionRuntimeMs": 1135, + "measuredRuntimeMs": 1994, + "budget": { + "status": "bounded", + "maxRuntimeMs": 50000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.support-intake", + "checkCount": 1, + "setupRuntimeMs": 0, + "criterionRuntimeMs": 441, + "measuredRuntimeMs": 441, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.support-triage", + "checkCount": 3, + "setupRuntimeMs": 927, + "criterionRuntimeMs": 10071, + "measuredRuntimeMs": 10998, + "budget": { + "status": "bounded", + "maxRuntimeMs": 45000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.access-control", + "checkCount": 21, + "setupRuntimeMs": 27625, + "criterionRuntimeMs": 212621, + "measuredRuntimeMs": 240246, + "budget": { + "status": "bounded", + "maxRuntimeMs": 464000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.concurrency-safety", + "checkCount": 6, + "setupRuntimeMs": 24565, + "criterionRuntimeMs": 58044, + "measuredRuntimeMs": 82609, + "budget": { + "status": "bounded", + "maxRuntimeMs": 125000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.external-data-sync", + "checkCount": 3, + "setupRuntimeMs": 670, + "criterionRuntimeMs": 28234, + "measuredRuntimeMs": 28904, + "budget": { + "status": "bounded", + "maxRuntimeMs": 105000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.live-state", + "checkCount": 11, + "setupRuntimeMs": 20495, + "criterionRuntimeMs": 6782, + "measuredRuntimeMs": 27277, + "budget": { + "status": "bounded", + "maxRuntimeMs": 184000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.search-ordering", + "checkCount": 1, + "setupRuntimeMs": 20800, + "criterionRuntimeMs": 5194, + "measuredRuntimeMs": 25994, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.state-durability", + "checkCount": 10, + "setupRuntimeMs": 11999, + "criterionRuntimeMs": 64392, + "measuredRuntimeMs": 76391, + "budget": { + "status": "bounded", + "maxRuntimeMs": 768000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.transactional-integrity", + "checkCount": 6, + "setupRuntimeMs": 24082, + "criterionRuntimeMs": 30891, + "measuredRuntimeMs": 54973, + "budget": { + "status": "bounded", + "maxRuntimeMs": 100000 + }, + "exceeded": false + } + ] + }, + "mutations": null + } + ], + "stable": true, + "sameImage": true, + "sameHarness": true, + "harnessSha256": "c911977ee8f6b0894c581b7c9d95957441c8052f7404e7ebff17f00cec4d86e5", + "qualifiedCheckKeys": [ + "ecommerce.feature.accounts.accounts.1a", + "ecommerce.feature.accounts.accounts.1b", + "ecommerce.feature.accounts.accounts.1c", + "ecommerce.feature.accounts.accounts.1d", + "ecommerce.feature.cart-checkout.cart.4a", + "ecommerce.feature.cart-checkout.cart.4d", + "ecommerce.feature.catalog.catalog-ranking.2b", + "ecommerce.feature.catalog.catalog-search.2d", + "ecommerce.feature.catalog.catalog-values.2a", + "ecommerce.feature.purchasing.purchase-order.3c", + "ecommerce.feature.reviews.reviews.6a", + "ecommerce.feature.warehouse-admin.admin-write.103a", + "ecommerce.feature.warehouse-admin.warehouse-view.7b", + "ecommerce.inventory-operations.operational-views.5c", + "ecommerce.inventory-operations.operational-views.5d", + "ecommerce.inventory-operations.operational-views.5e", + "ecommerce.inventory-operations.operational-views.5f", + "ecommerce.inventory-operations.shipping-accounting.202e", + "ecommerce.inventory-operations.stock-conservation.202a", + "ecommerce.inventory-operations.stock-conservation.202b", + "ecommerce.inventory-operations.stock-conservation.202c", + "ecommerce.inventory-operations.stock-conservation.202d", + "ecommerce.inventory-operations.warehouse-transfer.2a", + "ecommerce.l3.deferred-access.scheduled-work-access.317a", + "ecommerce.l3.deferred-durability.restart-survival.311a", + "ecommerce.l3.deferred-integrity.exactly-once.311a", + "ecommerce.l3.scheduled-restocks.scheduled-restocks.302a", + "ecommerce.l3.scheduled-restocks.scheduled-restocks.305a", + "ecommerce.l3.scheduled-restocks.scheduled-restocks.306a", + "ecommerce.l3.server-time.server-time.312a", + "ecommerce.operations-access.fulfilment-queue.1b", + "ecommerce.operations-access.fulfilment-queue.1c", + "ecommerce.operations-access.operator-authorization.201a", + "ecommerce.operations-access.operator-authorization.201c", + "ecommerce.operations-access.order-owner.204a", + "ecommerce.progression.catalog-management.catalog-management.622a", + "ecommerce.progression.catalog-management.catalog-management.622b", + "ecommerce.progression.customer-profile.customer-profile.620c", + "ecommerce.progression.faceted-search.faceted-search.401a", + "ecommerce.progression.faceted-search.faceted-search.402a", + "ecommerce.progression.managed-support.managed-support.613c", + "ecommerce.progression.notification-preferences.notification-preferences.630c", + "ecommerce.progression.promotion-rules.promotion-rule-values.620a", + "ecommerce.progression.review-access-specifications.review-eligibility-direct.618a", + "ecommerce.progression.review-access-specifications.stored-review-script.9180a", + "ecommerce.progression.staff-access.staff-access.601a", + "ecommerce.progression.staff-roles.staff-roles.621c", + "ecommerce.progression.stock-alerts.stock-alert-delivery.631c", + "ecommerce.progression.support-history.support-history.612c", + "ecommerce.progression.support-intake.support-intake.610a", + "ecommerce.progression.support-triage.support-assignment.611a", + "ecommerce.progression.support-triage.support-priority.611b", + "ecommerce.progression.support-triage.support-status.611c", + "ecommerce.returns-pricing.cancellation-and-return.3a", + "ecommerce.returns-pricing.cancellation-and-return.3b", + "ecommerce.returns-pricing.refund-accounting.203a", + "ecommerce.spec.access-control.cart-boundary.109a", + "ecommerce.spec.access-control.cart-boundary.109b", + "ecommerce.spec.access-control.customer-profile-privacy.620b", + "ecommerce.spec.access-control.fulfilment-area-boundary.1d", + "ecommerce.spec.access-control.managed-support-privacy.613b", + "ecommerce.spec.access-control.notification-preferences-privacy.630b", + "ecommerce.spec.access-control.order-ownership.106a", + "ecommerce.spec.access-control.promotion-management-boundary.620b", + "ecommerce.spec.access-control.purchase-attribution.102a", + "ecommerce.spec.access-control.purchase-session.101a", + "ecommerce.spec.access-control.review-eligibility.108a", + "ecommerce.spec.access-control.review-eligibility.108b", + "ecommerce.spec.access-control.signed-out-purchase.3a", + "ecommerce.spec.access-control.staff-area-boundary.601b", + "ecommerce.spec.access-control.staff-role-boundary.621b", + "ecommerce.spec.access-control.staff-role-revocation.621d", + "ecommerce.spec.access-control.stock-alert-privacy.631b", + "ecommerce.spec.access-control.support-history-logout.612d", + "ecommerce.spec.access-control.support-history-privacy.612b", + "ecommerce.spec.access-control.warehouse-area-boundary.7a", + "ecommerce.spec.access-control.warehouse-write-boundary.103b", + "ecommerce.spec.concurrency-safety.duplicate-checkout.203a", + "ecommerce.spec.concurrency-safety.duplicate-checkout.203b", + "ecommerce.spec.concurrency-safety.last-unit.201a", + "ecommerce.spec.concurrency-safety.last-unit.201b", + "ecommerce.spec.concurrency-safety.last-unit.201c", + "ecommerce.spec.concurrency-safety.restock-race.202a", + "ecommerce.spec.external-data-sync.external-stock.901a", + "ecommerce.spec.external-data-sync.external-stock.901c", + "ecommerce.spec.external-data-sync.external-stock.901d", + "ecommerce.spec.live-state.fulfilment-queue.1a", + "ecommerce.spec.live-state.inventory-dashboard.5a", + "ecommerce.spec.live-state.managed-support.613a", + "ecommerce.spec.live-state.open-list.902a", + "ecommerce.spec.live-state.purchase-stock.3b", + "ecommerce.spec.live-state.ranking.2c", + "ecommerce.spec.live-state.rating.6c", + "ecommerce.spec.live-state.sales-dashboard.5b", + "ecommerce.spec.live-state.shared-cart.4c", + "ecommerce.spec.live-state.stock-transfers.2b", + "ecommerce.spec.live-state.warehouse-stock.7c", + "ecommerce.spec.search-ordering.search-ordering.402b", + "ecommerce.spec.state-durability.account-state-recovery.105a", + "ecommerce.spec.state-durability.account-state-recovery.105b", + "ecommerce.spec.state-durability.cart-reload.4b", + "ecommerce.spec.state-durability.checkout-crash-durability.910b", + "ecommerce.spec.state-durability.checkout-crash-integrity.910a", + "ecommerce.spec.state-durability.customer-profile-reload.620a", + "ecommerce.spec.state-durability.notification-preferences-reload.630a", + "ecommerce.spec.state-durability.session-reload.1e", + "ecommerce.spec.state-durability.staff-role-reload.621a", + "ecommerce.spec.state-durability.support-history-reload.612a", + "ecommerce.spec.transactional-integrity.books-balance.107a", + "ecommerce.spec.transactional-integrity.books-balance.107b", + "ecommerce.spec.transactional-integrity.server-price.104a", + "ecommerce.spec.transactional-integrity.stock-alert-deduplication.631a", + "ecommerce.spec.transactional-integrity.stock-transfer-overdraw.2c", + "ecommerce.spec.transactional-integrity.unique-review.6b" + ], + "featureCatalog": { + "contentSha256": "8671f7883c2e5a24474a546ef1517407cd9334258e1a7cfe91e292a9af1952f2", + "id": "ecommerce.questlines" + }, + "diagnostic": false, + "ok": true + } +} diff --git a/tools/stack-bench/qualification-evidence/ecommerce-l3-7cd96d01b/spacetime-mutation.json b/tools/stack-bench/qualification-evidence/ecommerce-l3-7cd96d01b/spacetime-mutation.json new file mode 100644 index 00000000000..e9a8b633e44 --- /dev/null +++ b/tools/stack-bench/qualification-evidence/ecommerce-l3-7cd96d01b/spacetime-mutation.json @@ -0,0 +1,960 @@ +{ + "artifactSchemaVersion": 2, + "kind": "reference_qualification", + "id": "reference-live-spacetime-20260917222454-31", + "attempt": { + "id": "reference-live-spacetime-20260917222454-31", + "parentId": null + }, + "timestamps": { + "startedAt": "2026-09-17T22:24:54.381Z", + "completedAt": "2026-09-17T23:21:38.675Z" + }, + "identities": { + "engine": { + "id": "stack-bench", + "sha256": "ee2e27156ab1080f508abaf810d87c114aba21846768f33897be0581aeb7a795" + }, + "recipe": { + "id": "ecommerce.progression-catalog", + "sha256": "104589b973c1e7dd1a2410659759989eb0de08b16efeda3131777f82858a0a8b" + }, + "fixture": { + "id": "ecommerce-reference-spacetime", + "sha256": "7ba1f548e89f461b95b5caf843b0fbcf2b81278428d02869d7f47e1a199eaf6e" + }, + "calibration": { + "id": "ecommerce.dependency-l3-calibration", + "sha256": "1b0b4927efbcabbaf8975f4ffbb0ebc77d6af2679fc0f9cac9ef492d751933e0" + }, + "experiment": null, + "agentAdapter": null, + "stackAdapter": { + "id": "spacetime", + "sha256": null + }, + "packs": [] + }, + "payload": { + "fixture": "ecommerce-reference-spacetime", + "fixtureSha256": "7ba1f548e89f461b95b5caf843b0fbcf2b81278428d02869d7f47e1a199eaf6e", + "requiredRepetitions": 1, + "isolation": "docker", + "runner": { + "schemaVersion": 1, + "mode": "appliance", + "platform": "linux", + "architecture": "x64", + "hostname": "docker-desktop", + "dockerEngineVersion": "29.6.2", + "dockerOs": "linux", + "dockerArchitecture": "x86_64", + "kernelVersion": "6.6.87.2-microsoft-standard-WSL2", + "cpuCount": 32, + "memoryBytes": 49232842752, + "containersRunning": 12, + "packageRegistry": "http://127.0.0.1:4873/" + }, + "qualificationScope": { + "checksSha256": "ce9efe7f66ef111ce68dc65dcb22b48e20e4e89e68bd62fb7f7776e6a379f64d", + "executableSha256": "8361afc1146cd380285ecc5e8ad0f0bad7fb056c444d7439acd4611ec40914af", + "kind": "mutation", + "mutationSha256": "c845a507863287e3a900498d1cca31e058f1b745bc1b5d8ba048ba79e0734e23", + "recipe": { + "contentSha256": "104589b973c1e7dd1a2410659759989eb0de08b16efeda3131777f82858a0a8b", + "id": "ecommerce.progression-catalog" + }, + "schemaVersion": 3, + "stack": { + "id": "spacetime", + "reference": { + "id": "ecommerce-reference-spacetime", + "sourceSha256": "7ba1f548e89f461b95b5caf843b0fbcf2b81278428d02869d7f47e1a199eaf6e" + }, + "version": "1.4.0" + }, + "sha256": "6a5f0a0e549b88fda1f495f788b63ee8cf1a34038366d3eaaa896a7b6d16a23c" + }, + "mutationControl": true, + "runs": [ + { + "repetition": 1, + "output": "ecommerce-l3-104589b973c1-spacetime-mutation.runs/r1-workers", + "durationMs": 3404189, + "processError": null, + "harnessSha256Before": "c911977ee8f6b0894c581b7c9d95957441c8052f7404e7ebff17f00cec4d86e5", + "harnessSha256After": "c911977ee8f6b0894c581b7c9d95957441c8052f7404e7ebff17f00cec4d86e5", + "ok": true, + "failures": [], + "runId": "reference-live-spacetime-20260917222454-31", + "score": "183/183", + "imageId": "sha256:32ff9a9e519ba9d1af2fe72f24622caa8ca7a9f2baf2338c6b1e0435e6ac5455", + "criteria": 114, + "zeroPointCriteria": 0, + "fingerprint": "3197a361efd9c27179e97087a9e9e342476520f9b1ae1fef4e358b08893058a8", + "outcome": "passed", + "packRuntime": { + "schemaVersion": 1, + "metric": "pack-check-wall-clock-sum-v1", + "packs": [ + { + "id": "ecommerce.feature.accounts", + "checkCount": 4, + "setupRuntimeMs": 847, + "criterionRuntimeMs": 15069, + "measuredRuntimeMs": 15916, + "budget": { + "status": "bounded", + "maxRuntimeMs": 18000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.cart", + "checkCount": 1, + "setupRuntimeMs": 389, + "criterionRuntimeMs": 6058, + "measuredRuntimeMs": 6447, + "budget": { + "status": "bounded", + "maxRuntimeMs": 42000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.catalog-discovery", + "checkCount": 2, + "setupRuntimeMs": 1, + "criterionRuntimeMs": 1978, + "measuredRuntimeMs": 1979, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.catalog-items", + "checkCount": 1, + "setupRuntimeMs": 0, + "criterionRuntimeMs": 263, + "measuredRuntimeMs": 263, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.checkout", + "checkCount": 1, + "setupRuntimeMs": 389, + "criterionRuntimeMs": 6287, + "measuredRuntimeMs": 6676, + "budget": { + "status": "bounded", + "maxRuntimeMs": 42000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.purchasing", + "checkCount": 1, + "setupRuntimeMs": 287, + "criterionRuntimeMs": 1150, + "measuredRuntimeMs": 1437, + "budget": { + "status": "bounded", + "maxRuntimeMs": 24000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.reviews", + "checkCount": 1, + "setupRuntimeMs": 1692, + "criterionRuntimeMs": 383, + "measuredRuntimeMs": 2075, + "budget": { + "status": "bounded", + "maxRuntimeMs": 22000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.warehouse-admin", + "checkCount": 2, + "setupRuntimeMs": 1169, + "criterionRuntimeMs": 4716, + "measuredRuntimeMs": 5885, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.inventory-dashboard", + "checkCount": 1, + "setupRuntimeMs": 5345, + "criterionRuntimeMs": 8, + "measuredRuntimeMs": 5353, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.order-cancellation-features", + "checkCount": 2, + "setupRuntimeMs": 819, + "criterionRuntimeMs": 12085, + "measuredRuntimeMs": 12904, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.recommendations", + "checkCount": 1, + "setupRuntimeMs": 270, + "criterionRuntimeMs": 5154, + "measuredRuntimeMs": 5424, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.sales-dashboard", + "checkCount": 2, + "setupRuntimeMs": 1830, + "criterionRuntimeMs": 5836, + "measuredRuntimeMs": 7666, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.stock-transfers-features", + "checkCount": 1, + "setupRuntimeMs": 376, + "criterionRuntimeMs": 1837, + "measuredRuntimeMs": 2213, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.deferred-access-specifications", + "checkCount": 1, + "setupRuntimeMs": 20780, + "criterionRuntimeMs": 4265, + "measuredRuntimeMs": 25045, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.deferred-durability-specifications", + "checkCount": 1, + "setupRuntimeMs": 125191, + "criterionRuntimeMs": 42318, + "measuredRuntimeMs": 167509, + "budget": { + "status": "bounded", + "maxRuntimeMs": 720000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.deferred-integrity-specifications", + "checkCount": 1, + "setupRuntimeMs": 40586, + "criterionRuntimeMs": 37161, + "measuredRuntimeMs": 77747, + "budget": { + "status": "bounded", + "maxRuntimeMs": 400000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.scheduled-restocks-features", + "checkCount": 3, + "setupRuntimeMs": 61432, + "criterionRuntimeMs": 70359, + "measuredRuntimeMs": 131791, + "budget": { + "status": "bounded", + "maxRuntimeMs": 150000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.server-time-specifications", + "checkCount": 1, + "setupRuntimeMs": 26019, + "criterionRuntimeMs": 114901, + "measuredRuntimeMs": 140920, + "budget": { + "status": "bounded", + "maxRuntimeMs": 300000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.cancellation-accounting-specifications", + "checkCount": 1, + "setupRuntimeMs": 693, + "criterionRuntimeMs": 12272, + "measuredRuntimeMs": 12965, + "budget": { + "status": "bounded", + "maxRuntimeMs": 24000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.catalog-management", + "checkCount": 2, + "setupRuntimeMs": 3701, + "criterionRuntimeMs": 26, + "measuredRuntimeMs": 3727, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.customer-profile", + "checkCount": 1, + "setupRuntimeMs": 462, + "criterionRuntimeMs": 5071, + "measuredRuntimeMs": 5533, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.faceted-search", + "checkCount": 2, + "setupRuntimeMs": 44408, + "criterionRuntimeMs": 25589, + "measuredRuntimeMs": 69997, + "budget": { + "status": "bounded", + "maxRuntimeMs": 141000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.fulfilment-queue", + "checkCount": 2, + "setupRuntimeMs": 1141, + "criterionRuntimeMs": 28680, + "measuredRuntimeMs": 29821, + "budget": { + "status": "bounded", + "maxRuntimeMs": 76000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.inventory-conservation-specifications", + "checkCount": 5, + "setupRuntimeMs": 2301, + "criterionRuntimeMs": 55495, + "measuredRuntimeMs": 57796, + "budget": { + "status": "bounded", + "maxRuntimeMs": 138000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.managed-support", + "checkCount": 1, + "setupRuntimeMs": 800, + "criterionRuntimeMs": 6783, + "measuredRuntimeMs": 7583, + "budget": { + "status": "bounded", + "maxRuntimeMs": 55000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.notification-preferences", + "checkCount": 1, + "setupRuntimeMs": 580, + "criterionRuntimeMs": 5075, + "measuredRuntimeMs": 5655, + "budget": { + "status": "bounded", + "maxRuntimeMs": 40000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.operations-access-specifications", + "checkCount": 3, + "setupRuntimeMs": 9606, + "criterionRuntimeMs": 38478, + "measuredRuntimeMs": 48084, + "budget": { + "status": "bounded", + "maxRuntimeMs": 98000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.promotion-rules", + "checkCount": 1, + "setupRuntimeMs": 497, + "criterionRuntimeMs": 351, + "measuredRuntimeMs": 848, + "budget": { + "status": "bounded", + "maxRuntimeMs": 45000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.review-access-specifications", + "checkCount": 2, + "setupRuntimeMs": 8645, + "criterionRuntimeMs": 10943, + "measuredRuntimeMs": 19588, + "budget": { + "status": "bounded", + "maxRuntimeMs": 82000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.staff-access", + "checkCount": 1, + "setupRuntimeMs": 0, + "criterionRuntimeMs": 686, + "measuredRuntimeMs": 686, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.staff-roles", + "checkCount": 1, + "setupRuntimeMs": 514, + "criterionRuntimeMs": 27, + "measuredRuntimeMs": 541, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.stock-alerts", + "checkCount": 1, + "setupRuntimeMs": 5569, + "criterionRuntimeMs": 12622, + "measuredRuntimeMs": 18191, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.support-history", + "checkCount": 1, + "setupRuntimeMs": 889, + "criterionRuntimeMs": 1580, + "measuredRuntimeMs": 2469, + "budget": { + "status": "bounded", + "maxRuntimeMs": 50000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.support-intake", + "checkCount": 1, + "setupRuntimeMs": 0, + "criterionRuntimeMs": 447, + "measuredRuntimeMs": 447, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.support-triage", + "checkCount": 3, + "setupRuntimeMs": 855, + "criterionRuntimeMs": 11072, + "measuredRuntimeMs": 11927, + "budget": { + "status": "bounded", + "maxRuntimeMs": 45000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.access-control", + "checkCount": 21, + "setupRuntimeMs": 28200, + "criterionRuntimeMs": 224542, + "measuredRuntimeMs": 252742, + "budget": { + "status": "bounded", + "maxRuntimeMs": 464000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.concurrency-safety", + "checkCount": 6, + "setupRuntimeMs": 28042, + "criterionRuntimeMs": 64894, + "measuredRuntimeMs": 92936, + "budget": { + "status": "bounded", + "maxRuntimeMs": 125000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.external-data-sync", + "checkCount": 3, + "setupRuntimeMs": 690, + "criterionRuntimeMs": 33123, + "measuredRuntimeMs": 33813, + "budget": { + "status": "bounded", + "maxRuntimeMs": 105000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.live-state", + "checkCount": 11, + "setupRuntimeMs": 21103, + "criterionRuntimeMs": 7681, + "measuredRuntimeMs": 28784, + "budget": { + "status": "bounded", + "maxRuntimeMs": 184000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.search-ordering", + "checkCount": 1, + "setupRuntimeMs": 21716, + "criterionRuntimeMs": 5241, + "measuredRuntimeMs": 26957, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.state-durability", + "checkCount": 10, + "setupRuntimeMs": 9361, + "criterionRuntimeMs": 57544, + "measuredRuntimeMs": 66905, + "budget": { + "status": "bounded", + "maxRuntimeMs": 768000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.transactional-integrity", + "checkCount": 6, + "setupRuntimeMs": 25318, + "criterionRuntimeMs": 35996, + "measuredRuntimeMs": 61314, + "budget": { + "status": "bounded", + "maxRuntimeMs": 100000 + }, + "exceeded": false + } + ] + }, + "mutations": { + "caught": 119, + "total": 119 + }, + "baselineDurationMs": 2351041, + "baselineOutput": "ecommerce-l3-104589b973c1-spacetime-mutation.runs/r1", + "baselineHarnessSha256Before": "c911977ee8f6b0894c581b7c9d95957441c8052f7404e7ebff17f00cec4d86e5", + "baselineHarnessSha256After": "c911977ee8f6b0894c581b7c9d95957441c8052f7404e7ebff17f00cec4d86e5", + "workers": [ + { + "index": 0, + "runIndex": 0, + "artifact": "ecommerce-l3-104589b973c1-spacetime-mutation.runs/r1-workers/w1.json", + "mutationIds": [ + "staff-admin-access-survives-role-removal", + "catalog-seeds-the-wrong-air-purifier-price", + "existing-cart-line-does-not-increment-basic-cart", + "warehouse-view-omits-west", + "admin-revenue-double-counts-every-order", + "stock-subscription-snapshotted-once", + "cancel-restores-stock-but-keeps-pending-status", + "operator-authorization-allows-customer-shipping", + "customers-can-schedule-restocks", + "catalog-variants-are-discarded", + "managed-support-live-replies-stay-at-initial-snapshot", + "staff-can-assign-roles", + "support-priority-is-discarded", + "category-totals-count-only-since-the-dashboard-opened", + "warehouse-totals-are-frozen-at-page-load" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-104589b973c1-spacetime-mutation.runs/r1-workers/w1.stdout.log", + "stderr": "ecommerce-l3-104589b973c1-spacetime-mutation.runs/r1-workers/w1.stderr.log" + } + }, + { + "index": 1, + "runIndex": 1, + "artifact": "ecommerce-l3-104589b973c1-spacetime-mutation.runs/r1-workers/w2.json", + "mutationIds": [ + "shipping-counts-sale-twice", + "catalog-tie-breaks-in-reverse-alphabetical-order--01-catalog-ranking", + "cart-is-deleted-when-owner-disconnects", + "guest-purchase-falls-back-to-the-admin-account", + "purchases-do-not-leave-the-warehouses", + "stock-view-ignores-update-across-app-server-stop", + "cancelled-order-remains-in-revenue-feature", + "transfer-debits-source-without-crediting-existing-destination", + "scheduled-restock-execution-queue-is-process-local", + "profile-is-lost-on-fresh-account-login", + "notification-preferences-are-not-saved", + "stock-alert-delivery-is-suppressed", + "support-status-is-discarded", + "profile-summary-ignores-a-profile-saved-this-session", + "transfer-skips-the-source-holding-check" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-104589b973c1-spacetime-mutation.runs/r1-workers/w2.stdout.log", + "stderr": "ecommerce-l3-104589b973c1-spacetime-mutation.runs/r1-workers/w2.stderr.log" + } + }, + { + "index": 2, + "runIndex": 2, + "artifact": "ecommerce-l3-104589b973c1-spacetime-mutation.runs/r1-workers/w3.json", + "mutationIds": [ + "restock-client-snapshot-overwrites-concurrent-purchases", + "catalog-tie-breaks-in-reverse-alphabetical-order--01-core", + "signin-binds-the-second-client-to-a-different-account", + "direct-purchases-are-attributed-to-the-system-account", + "review-purchase-eligibility-is-not-checked", + "stock-view-keeps-pre-reconnect-snapshot", + "cancelled-order-remains-in-revenue-invariant", + "recommendations-ignore-pending-purchases", + "completed-restock-remains-pending", + "customer-profile-view-leaks-another-account", + "notification-preferences-leak-across-accounts", + "stock-alert-is-sent-after-every-restock", + "nonpositive-cart-quantity-is-treated-as-removal", + "stored-support-replies-are-hidden-after-reload", + "support-history-leaks-to-signed-out-visitors" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-104589b973c1-spacetime-mutation.runs/r1-workers/w3.stdout.log", + "stderr": "ecommerce-l3-104589b973c1-spacetime-mutation.runs/r1-workers/w3.stderr.log" + } + }, + { + "index": 3, + "runIndex": 3, + "artifact": "ecommerce-l3-104589b973c1-spacetime-mutation.runs/r1-workers/w4.json", + "mutationIds": [ + "signup-binds-the-new-account-to-the-admin-session", + "purchase-does-not-update-ranking-count", + "checkout-does-not-empty-the-basic-cart", + "direct-restock-does-not-require-an-admin", + "eligible-review-is-accepted-without-being-stored", + "open-review-list-snapshots-on-selection", + "operator-authorization-allows-customer-transfer", + "purchases-do-not-affect-best-sellers", + "pending-restock-timer-is-static", + "faceted-search-ignores-category", + "customers-can-create-promotions", + "stock-alerts-are-visible-to-other-customers", + "admin-restock-preserves-existing-stock", + "saving-notification-preferences-resets-the-toggles", + "checkout-crash-integrity" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-104589b973c1-spacetime-mutation.runs/r1-workers/w4.stdout.log", + "stderr": "ecommerce-l3-104589b973c1-spacetime-mutation.runs/r1-workers/w4.stderr.log" + } + }, + { + "index": 4, + "runIndex": 4, + "artifact": "ecommerce-l3-104589b973c1-spacetime-mutation.runs/r1-workers/w5.json", + "mutationIds": [ + "duplicate-signup-is-silently-ignored", + "signed-out-purchase-bypasses-account-check", + "new-review-is-accepted-without-being-stored", + "direct-purchase-ignores-the-stored-price", + "cart-line-lookup-ignores-cart-ownership", + "open-review-list-renders-each-review-twice", + "customer-can-ship-order-direct-1-1", + "queue-warehouse-reports-west", + "due-restock-omits-ledger-entry", + "active-search-uses-purchase-ranking", + "promotion-rule-stores-the-wrong-discount", + "support-history-is-lost-on-fresh-account-login", + "direct-review-access-is-not-checked", + "saving-a-staff-role-snaps-the-input-back-to-the-stored-role", + "checkout-crash-durability" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-104589b973c1-spacetime-mutation.runs/r1-workers/w5.stdout.log", + "stderr": "ecommerce-l3-104589b973c1-spacetime-mutation.runs/r1-workers/w5.stderr.log" + } + }, + { + "index": 5, + "runIndex": 5, + "artifact": "ecommerce-l3-104589b973c1-spacetime-mutation.runs/r1-workers/w6.json", + "mutationIds": [ + "signin-does-not-verify-the-password", + "buy-now-creates-orders-without-reserving-stock--01-buying", + "repeat-review-inserts-a-second-row", + "account-state-token-is-not-restored-after-reload", + "purchase-does-not-reserve-stock-last-unit", + "cancel-does-not-restore-stock-feature", + "customer-can-cancel-foreign-order-1-1", + "transfer-creates-stock-during-race", + "cancelled-restock-remains-pending", + "faceted-search-next-page-does-not-advance", + "staff-cannot-open-staff-tools", + "support-history-leaks-across-customers", + "support-history-rows-are-hidden", + "fulfilment-queue-is-frozen-at-page-load", + "review-script-unsafe-render" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-104589b973c1-spacetime-mutation.runs/r1-workers/w6.stdout.log", + "stderr": "ecommerce-l3-104589b973c1-spacetime-mutation.runs/r1-workers/w6.stderr.log" + } + }, + { + "index": 6, + "runIndex": 6, + "artifact": "ecommerce-l3-104589b973c1-spacetime-mutation.runs/r1-workers/w7.json", + "mutationIds": [ + "signout-keeps-the-account-session", + "restock-race-records-wrong-order-total", + "review-average-counts-rows-instead-of-ratings", + "reconnect-discards-the-visible-account-state", + "existing-cart-line-does-not-increment", + "cancellation-accounting-loses-stock-restoration", + "ship-acknowledges-without-changing-status", + "catalog-search-ignores-the-query", + "restart-restock-runs-early", + "managed-support-leaks-and-accepts-cross-account-replies", + "customers-can-open-staff-tools", + "visitor-support-reference-is-hidden", + "authorized-restock-does-not-change-stock", + "low-stock-list-is-frozen-at-page-load", + "review-script-reject-all" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-104589b973c1-spacetime-mutation.runs/r1-workers/w7.stdout.log", + "stderr": "ecommerce-l3-104589b973c1-spacetime-mutation.runs/r1-workers/w7.stderr.log" + } + }, + { + "index": 7, + "runIndex": 7, + "artifact": "ecommerce-l3-104589b973c1-spacetime-mutation.runs/r1-workers/w8.json", + "mutationIds": [ + "session-token-is-not-persisted-for-reload", + "buy-now-records-the-wrong-order-total", + "every-signed-in-customer-is-treated-as-an-admin", + "order-views-return-every-customers-orders", + "checkout-does-not-empty-cart", + "cancel-does-not-restore-stock-fresh-client", + "progression-customer-sees-fulfilment-content", + "admin-total-stock-is-not-rendered", + "catalog-product-is-not-published", + "managed-support-replies-are-empty", + "administrator-role-assignment-is-discarded", + "support-assignment-is-discarded", + "low-stock-threshold-is-two-units", + "category-totals-are-frozen-at-page-load" + ], + "ok": true, + "logs": { + "stdout": "ecommerce-l3-104589b973c1-spacetime-mutation.runs/r1-workers/w8.stdout.log", + "stderr": "ecommerce-l3-104589b973c1-spacetime-mutation.runs/r1-workers/w8.stderr.log" + } + } + ] + } + ], + "stable": true, + "sameImage": true, + "sameHarness": true, + "harnessSha256": "c911977ee8f6b0894c581b7c9d95957441c8052f7404e7ebff17f00cec4d86e5", + "qualifiedCheckKeys": [ + "ecommerce.feature.accounts.accounts.1a", + "ecommerce.feature.accounts.accounts.1b", + "ecommerce.feature.accounts.accounts.1c", + "ecommerce.feature.accounts.accounts.1d", + "ecommerce.feature.cart-checkout.cart.4a", + "ecommerce.feature.cart-checkout.cart.4d", + "ecommerce.feature.catalog.catalog-ranking.2b", + "ecommerce.feature.catalog.catalog-search.2d", + "ecommerce.feature.catalog.catalog-values.2a", + "ecommerce.feature.purchasing.purchase-order.3c", + "ecommerce.feature.reviews.reviews.6a", + "ecommerce.feature.warehouse-admin.admin-write.103a", + "ecommerce.feature.warehouse-admin.warehouse-view.7b", + "ecommerce.inventory-operations.operational-views.5c", + "ecommerce.inventory-operations.operational-views.5d", + "ecommerce.inventory-operations.operational-views.5e", + "ecommerce.inventory-operations.operational-views.5f", + "ecommerce.inventory-operations.shipping-accounting.202e", + "ecommerce.inventory-operations.stock-conservation.202a", + "ecommerce.inventory-operations.stock-conservation.202b", + "ecommerce.inventory-operations.stock-conservation.202c", + "ecommerce.inventory-operations.stock-conservation.202d", + "ecommerce.inventory-operations.warehouse-transfer.2a", + "ecommerce.l3.deferred-access.scheduled-work-access.317a", + "ecommerce.l3.deferred-durability.restart-survival.311a", + "ecommerce.l3.deferred-integrity.exactly-once.311a", + "ecommerce.l3.scheduled-restocks.scheduled-restocks.302a", + "ecommerce.l3.scheduled-restocks.scheduled-restocks.305a", + "ecommerce.l3.scheduled-restocks.scheduled-restocks.306a", + "ecommerce.l3.server-time.server-time.312a", + "ecommerce.operations-access.fulfilment-queue.1b", + "ecommerce.operations-access.fulfilment-queue.1c", + "ecommerce.operations-access.operator-authorization.201a", + "ecommerce.operations-access.operator-authorization.201c", + "ecommerce.operations-access.order-owner.204a", + "ecommerce.progression.catalog-management.catalog-management.622a", + "ecommerce.progression.catalog-management.catalog-management.622b", + "ecommerce.progression.customer-profile.customer-profile.620c", + "ecommerce.progression.faceted-search.faceted-search.401a", + "ecommerce.progression.faceted-search.faceted-search.402a", + "ecommerce.progression.managed-support.managed-support.613c", + "ecommerce.progression.notification-preferences.notification-preferences.630c", + "ecommerce.progression.promotion-rules.promotion-rule-values.620a", + "ecommerce.progression.review-access-specifications.review-eligibility-direct.618a", + "ecommerce.progression.review-access-specifications.stored-review-script.9180a", + "ecommerce.progression.staff-access.staff-access.601a", + "ecommerce.progression.staff-roles.staff-roles.621c", + "ecommerce.progression.stock-alerts.stock-alert-delivery.631c", + "ecommerce.progression.support-history.support-history.612c", + "ecommerce.progression.support-intake.support-intake.610a", + "ecommerce.progression.support-triage.support-assignment.611a", + "ecommerce.progression.support-triage.support-priority.611b", + "ecommerce.progression.support-triage.support-status.611c", + "ecommerce.returns-pricing.cancellation-and-return.3a", + "ecommerce.returns-pricing.cancellation-and-return.3b", + "ecommerce.returns-pricing.refund-accounting.203a", + "ecommerce.spec.access-control.cart-boundary.109a", + "ecommerce.spec.access-control.cart-boundary.109b", + "ecommerce.spec.access-control.customer-profile-privacy.620b", + "ecommerce.spec.access-control.fulfilment-area-boundary.1d", + "ecommerce.spec.access-control.managed-support-privacy.613b", + "ecommerce.spec.access-control.notification-preferences-privacy.630b", + "ecommerce.spec.access-control.order-ownership.106a", + "ecommerce.spec.access-control.promotion-management-boundary.620b", + "ecommerce.spec.access-control.purchase-attribution.102a", + "ecommerce.spec.access-control.purchase-session.101a", + "ecommerce.spec.access-control.review-eligibility.108a", + "ecommerce.spec.access-control.review-eligibility.108b", + "ecommerce.spec.access-control.signed-out-purchase.3a", + "ecommerce.spec.access-control.staff-area-boundary.601b", + "ecommerce.spec.access-control.staff-role-boundary.621b", + "ecommerce.spec.access-control.staff-role-revocation.621d", + "ecommerce.spec.access-control.stock-alert-privacy.631b", + "ecommerce.spec.access-control.support-history-logout.612d", + "ecommerce.spec.access-control.support-history-privacy.612b", + "ecommerce.spec.access-control.warehouse-area-boundary.7a", + "ecommerce.spec.access-control.warehouse-write-boundary.103b", + "ecommerce.spec.concurrency-safety.duplicate-checkout.203a", + "ecommerce.spec.concurrency-safety.duplicate-checkout.203b", + "ecommerce.spec.concurrency-safety.last-unit.201a", + "ecommerce.spec.concurrency-safety.last-unit.201b", + "ecommerce.spec.concurrency-safety.last-unit.201c", + "ecommerce.spec.concurrency-safety.restock-race.202a", + "ecommerce.spec.external-data-sync.external-stock.901a", + "ecommerce.spec.external-data-sync.external-stock.901c", + "ecommerce.spec.external-data-sync.external-stock.901d", + "ecommerce.spec.live-state.fulfilment-queue.1a", + "ecommerce.spec.live-state.inventory-dashboard.5a", + "ecommerce.spec.live-state.managed-support.613a", + "ecommerce.spec.live-state.open-list.902a", + "ecommerce.spec.live-state.purchase-stock.3b", + "ecommerce.spec.live-state.ranking.2c", + "ecommerce.spec.live-state.rating.6c", + "ecommerce.spec.live-state.sales-dashboard.5b", + "ecommerce.spec.live-state.shared-cart.4c", + "ecommerce.spec.live-state.stock-transfers.2b", + "ecommerce.spec.live-state.warehouse-stock.7c", + "ecommerce.spec.search-ordering.search-ordering.402b", + "ecommerce.spec.state-durability.account-state-recovery.105a", + "ecommerce.spec.state-durability.account-state-recovery.105b", + "ecommerce.spec.state-durability.cart-reload.4b", + "ecommerce.spec.state-durability.checkout-crash-durability.910b", + "ecommerce.spec.state-durability.checkout-crash-integrity.910a", + "ecommerce.spec.state-durability.customer-profile-reload.620a", + "ecommerce.spec.state-durability.notification-preferences-reload.630a", + "ecommerce.spec.state-durability.session-reload.1e", + "ecommerce.spec.state-durability.staff-role-reload.621a", + "ecommerce.spec.state-durability.support-history-reload.612a", + "ecommerce.spec.transactional-integrity.books-balance.107a", + "ecommerce.spec.transactional-integrity.books-balance.107b", + "ecommerce.spec.transactional-integrity.server-price.104a", + "ecommerce.spec.transactional-integrity.stock-alert-deduplication.631a", + "ecommerce.spec.transactional-integrity.stock-transfer-overdraw.2c", + "ecommerce.spec.transactional-integrity.unique-review.6b" + ], + "featureCatalog": { + "contentSha256": "8671f7883c2e5a24474a546ef1517407cd9334258e1a7cfe91e292a9af1952f2", + "id": "ecommerce.questlines" + }, + "diagnostic": false, + "ok": true + } +} diff --git a/tools/stack-bench/qualification-evidence/ecommerce-l3-7cd96d01b/spacetime-reference.json b/tools/stack-bench/qualification-evidence/ecommerce-l3-7cd96d01b/spacetime-reference.json new file mode 100644 index 00000000000..666d397e0cf --- /dev/null +++ b/tools/stack-bench/qualification-evidence/ecommerce-l3-7cd96d01b/spacetime-reference.json @@ -0,0 +1,736 @@ +{ + "artifactSchemaVersion": 2, + "kind": "reference_qualification", + "id": "reference-live-spacetime-20260917222454-31-reference", + "attempt": { + "id": "reference-live-spacetime-20260917222454-31-reference", + "parentId": null + }, + "timestamps": { + "startedAt": "2026-09-17T22:24:54.381Z", + "completedAt": "2026-09-17T23:21:38.676Z" + }, + "identities": { + "engine": { + "id": "stack-bench", + "sha256": "ee2e27156ab1080f508abaf810d87c114aba21846768f33897be0581aeb7a795" + }, + "recipe": { + "id": "ecommerce.progression-catalog", + "sha256": "104589b973c1e7dd1a2410659759989eb0de08b16efeda3131777f82858a0a8b" + }, + "fixture": { + "id": "ecommerce-reference-spacetime", + "sha256": "7ba1f548e89f461b95b5caf843b0fbcf2b81278428d02869d7f47e1a199eaf6e" + }, + "calibration": { + "id": "ecommerce.dependency-l3-calibration", + "sha256": "1b0b4927efbcabbaf8975f4ffbb0ebc77d6af2679fc0f9cac9ef492d751933e0" + }, + "experiment": null, + "agentAdapter": null, + "stackAdapter": { + "id": "spacetime", + "sha256": null + }, + "packs": [] + }, + "payload": { + "fixture": "ecommerce-reference-spacetime", + "fixtureSha256": "7ba1f548e89f461b95b5caf843b0fbcf2b81278428d02869d7f47e1a199eaf6e", + "requiredRepetitions": 1, + "isolation": "docker", + "runner": { + "schemaVersion": 1, + "mode": "appliance", + "platform": "linux", + "architecture": "x64", + "hostname": "docker-desktop", + "dockerEngineVersion": "29.6.2", + "dockerOs": "linux", + "dockerArchitecture": "x86_64", + "kernelVersion": "6.6.87.2-microsoft-standard-WSL2", + "cpuCount": 32, + "memoryBytes": 49232842752, + "containersRunning": 12, + "packageRegistry": "http://127.0.0.1:4873/" + }, + "qualificationScope": { + "checksSha256": "ce9efe7f66ef111ce68dc65dcb22b48e20e4e89e68bd62fb7f7776e6a379f64d", + "executableSha256": "8361afc1146cd380285ecc5e8ad0f0bad7fb056c444d7439acd4611ec40914af", + "kind": "reference", + "mutationSha256": null, + "recipe": { + "contentSha256": "104589b973c1e7dd1a2410659759989eb0de08b16efeda3131777f82858a0a8b", + "id": "ecommerce.progression-catalog" + }, + "schemaVersion": 3, + "stack": { + "id": "spacetime", + "reference": { + "id": "ecommerce-reference-spacetime", + "sourceSha256": "7ba1f548e89f461b95b5caf843b0fbcf2b81278428d02869d7f47e1a199eaf6e" + }, + "version": "1.4.0" + }, + "sha256": "38f9e609cc57c2076c4c678f698555c9bf69d2e3eb74120c4baa8217c072584c" + }, + "mutationControl": false, + "runs": [ + { + "repetition": 1, + "output": "ecommerce-l3-104589b973c1-spacetime-mutation.runs/r1", + "durationMs": 2351041, + "processError": null, + "harnessSha256Before": "c911977ee8f6b0894c581b7c9d95957441c8052f7404e7ebff17f00cec4d86e5", + "harnessSha256After": "c911977ee8f6b0894c581b7c9d95957441c8052f7404e7ebff17f00cec4d86e5", + "ok": true, + "failures": [], + "runId": "ecommerce-spacetime-run0-20260917222455-4ebb6f53", + "score": "183/183", + "imageId": "sha256:32ff9a9e519ba9d1af2fe72f24622caa8ca7a9f2baf2338c6b1e0435e6ac5455", + "criteria": 114, + "zeroPointCriteria": 0, + "fingerprint": "3197a361efd9c27179e97087a9e9e342476520f9b1ae1fef4e358b08893058a8", + "outcome": "passed", + "packRuntime": { + "schemaVersion": 1, + "metric": "pack-check-wall-clock-sum-v1", + "packs": [ + { + "id": "ecommerce.feature.accounts", + "checkCount": 4, + "setupRuntimeMs": 847, + "criterionRuntimeMs": 15069, + "measuredRuntimeMs": 15916, + "budget": { + "status": "bounded", + "maxRuntimeMs": 18000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.cart", + "checkCount": 1, + "setupRuntimeMs": 389, + "criterionRuntimeMs": 6058, + "measuredRuntimeMs": 6447, + "budget": { + "status": "bounded", + "maxRuntimeMs": 42000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.catalog-discovery", + "checkCount": 2, + "setupRuntimeMs": 1, + "criterionRuntimeMs": 1978, + "measuredRuntimeMs": 1979, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.catalog-items", + "checkCount": 1, + "setupRuntimeMs": 0, + "criterionRuntimeMs": 263, + "measuredRuntimeMs": 263, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.checkout", + "checkCount": 1, + "setupRuntimeMs": 389, + "criterionRuntimeMs": 6287, + "measuredRuntimeMs": 6676, + "budget": { + "status": "bounded", + "maxRuntimeMs": 42000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.purchasing", + "checkCount": 1, + "setupRuntimeMs": 287, + "criterionRuntimeMs": 1150, + "measuredRuntimeMs": 1437, + "budget": { + "status": "bounded", + "maxRuntimeMs": 24000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.reviews", + "checkCount": 1, + "setupRuntimeMs": 1692, + "criterionRuntimeMs": 383, + "measuredRuntimeMs": 2075, + "budget": { + "status": "bounded", + "maxRuntimeMs": 22000 + }, + "exceeded": false + }, + { + "id": "ecommerce.feature.warehouse-admin", + "checkCount": 2, + "setupRuntimeMs": 1169, + "criterionRuntimeMs": 4716, + "measuredRuntimeMs": 5885, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.inventory-dashboard", + "checkCount": 1, + "setupRuntimeMs": 5345, + "criterionRuntimeMs": 8, + "measuredRuntimeMs": 5353, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.order-cancellation-features", + "checkCount": 2, + "setupRuntimeMs": 819, + "criterionRuntimeMs": 12085, + "measuredRuntimeMs": 12904, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.recommendations", + "checkCount": 1, + "setupRuntimeMs": 270, + "criterionRuntimeMs": 5154, + "measuredRuntimeMs": 5424, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.sales-dashboard", + "checkCount": 2, + "setupRuntimeMs": 1830, + "criterionRuntimeMs": 5836, + "measuredRuntimeMs": 7666, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l2.stock-transfers-features", + "checkCount": 1, + "setupRuntimeMs": 376, + "criterionRuntimeMs": 1837, + "measuredRuntimeMs": 2213, + "budget": { + "status": "bounded", + "maxRuntimeMs": 86000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.deferred-access-specifications", + "checkCount": 1, + "setupRuntimeMs": 20780, + "criterionRuntimeMs": 4265, + "measuredRuntimeMs": 25045, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.deferred-durability-specifications", + "checkCount": 1, + "setupRuntimeMs": 125191, + "criterionRuntimeMs": 42318, + "measuredRuntimeMs": 167509, + "budget": { + "status": "bounded", + "maxRuntimeMs": 720000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.deferred-integrity-specifications", + "checkCount": 1, + "setupRuntimeMs": 40586, + "criterionRuntimeMs": 37161, + "measuredRuntimeMs": 77747, + "budget": { + "status": "bounded", + "maxRuntimeMs": 400000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.scheduled-restocks-features", + "checkCount": 3, + "setupRuntimeMs": 61432, + "criterionRuntimeMs": 70359, + "measuredRuntimeMs": 131791, + "budget": { + "status": "bounded", + "maxRuntimeMs": 150000 + }, + "exceeded": false + }, + { + "id": "ecommerce.l3.server-time-specifications", + "checkCount": 1, + "setupRuntimeMs": 26019, + "criterionRuntimeMs": 114901, + "measuredRuntimeMs": 140920, + "budget": { + "status": "bounded", + "maxRuntimeMs": 300000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.cancellation-accounting-specifications", + "checkCount": 1, + "setupRuntimeMs": 693, + "criterionRuntimeMs": 12272, + "measuredRuntimeMs": 12965, + "budget": { + "status": "bounded", + "maxRuntimeMs": 24000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.catalog-management", + "checkCount": 2, + "setupRuntimeMs": 3701, + "criterionRuntimeMs": 26, + "measuredRuntimeMs": 3727, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.customer-profile", + "checkCount": 1, + "setupRuntimeMs": 462, + "criterionRuntimeMs": 5071, + "measuredRuntimeMs": 5533, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.faceted-search", + "checkCount": 2, + "setupRuntimeMs": 44408, + "criterionRuntimeMs": 25589, + "measuredRuntimeMs": 69997, + "budget": { + "status": "bounded", + "maxRuntimeMs": 141000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.fulfilment-queue", + "checkCount": 2, + "setupRuntimeMs": 1141, + "criterionRuntimeMs": 28680, + "measuredRuntimeMs": 29821, + "budget": { + "status": "bounded", + "maxRuntimeMs": 76000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.inventory-conservation-specifications", + "checkCount": 5, + "setupRuntimeMs": 2301, + "criterionRuntimeMs": 55495, + "measuredRuntimeMs": 57796, + "budget": { + "status": "bounded", + "maxRuntimeMs": 138000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.managed-support", + "checkCount": 1, + "setupRuntimeMs": 800, + "criterionRuntimeMs": 6783, + "measuredRuntimeMs": 7583, + "budget": { + "status": "bounded", + "maxRuntimeMs": 55000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.notification-preferences", + "checkCount": 1, + "setupRuntimeMs": 580, + "criterionRuntimeMs": 5075, + "measuredRuntimeMs": 5655, + "budget": { + "status": "bounded", + "maxRuntimeMs": 40000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.operations-access-specifications", + "checkCount": 3, + "setupRuntimeMs": 9606, + "criterionRuntimeMs": 38478, + "measuredRuntimeMs": 48084, + "budget": { + "status": "bounded", + "maxRuntimeMs": 98000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.promotion-rules", + "checkCount": 1, + "setupRuntimeMs": 497, + "criterionRuntimeMs": 351, + "measuredRuntimeMs": 848, + "budget": { + "status": "bounded", + "maxRuntimeMs": 45000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.review-access-specifications", + "checkCount": 2, + "setupRuntimeMs": 8645, + "criterionRuntimeMs": 10943, + "measuredRuntimeMs": 19588, + "budget": { + "status": "bounded", + "maxRuntimeMs": 82000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.staff-access", + "checkCount": 1, + "setupRuntimeMs": 0, + "criterionRuntimeMs": 686, + "measuredRuntimeMs": 686, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.staff-roles", + "checkCount": 1, + "setupRuntimeMs": 514, + "criterionRuntimeMs": 27, + "measuredRuntimeMs": 541, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.stock-alerts", + "checkCount": 1, + "setupRuntimeMs": 5569, + "criterionRuntimeMs": 12622, + "measuredRuntimeMs": 18191, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.support-history", + "checkCount": 1, + "setupRuntimeMs": 889, + "criterionRuntimeMs": 1580, + "measuredRuntimeMs": 2469, + "budget": { + "status": "bounded", + "maxRuntimeMs": 50000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.support-intake", + "checkCount": 1, + "setupRuntimeMs": 0, + "criterionRuntimeMs": 447, + "measuredRuntimeMs": 447, + "budget": { + "status": "bounded", + "maxRuntimeMs": 30000 + }, + "exceeded": false + }, + { + "id": "ecommerce.progression.support-triage", + "checkCount": 3, + "setupRuntimeMs": 855, + "criterionRuntimeMs": 11072, + "measuredRuntimeMs": 11927, + "budget": { + "status": "bounded", + "maxRuntimeMs": 45000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.access-control", + "checkCount": 21, + "setupRuntimeMs": 28200, + "criterionRuntimeMs": 224542, + "measuredRuntimeMs": 252742, + "budget": { + "status": "bounded", + "maxRuntimeMs": 464000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.concurrency-safety", + "checkCount": 6, + "setupRuntimeMs": 28042, + "criterionRuntimeMs": 64894, + "measuredRuntimeMs": 92936, + "budget": { + "status": "bounded", + "maxRuntimeMs": 125000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.external-data-sync", + "checkCount": 3, + "setupRuntimeMs": 690, + "criterionRuntimeMs": 33123, + "measuredRuntimeMs": 33813, + "budget": { + "status": "bounded", + "maxRuntimeMs": 105000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.live-state", + "checkCount": 11, + "setupRuntimeMs": 21103, + "criterionRuntimeMs": 7681, + "measuredRuntimeMs": 28784, + "budget": { + "status": "bounded", + "maxRuntimeMs": 184000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.search-ordering", + "checkCount": 1, + "setupRuntimeMs": 21716, + "criterionRuntimeMs": 5241, + "measuredRuntimeMs": 26957, + "budget": { + "status": "bounded", + "maxRuntimeMs": 60000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.state-durability", + "checkCount": 10, + "setupRuntimeMs": 9361, + "criterionRuntimeMs": 57544, + "measuredRuntimeMs": 66905, + "budget": { + "status": "bounded", + "maxRuntimeMs": 768000 + }, + "exceeded": false + }, + { + "id": "ecommerce.spec.transactional-integrity", + "checkCount": 6, + "setupRuntimeMs": 25318, + "criterionRuntimeMs": 35996, + "measuredRuntimeMs": 61314, + "budget": { + "status": "bounded", + "maxRuntimeMs": 100000 + }, + "exceeded": false + } + ] + }, + "mutations": null + } + ], + "stable": true, + "sameImage": true, + "sameHarness": true, + "harnessSha256": "c911977ee8f6b0894c581b7c9d95957441c8052f7404e7ebff17f00cec4d86e5", + "qualifiedCheckKeys": [ + "ecommerce.feature.accounts.accounts.1a", + "ecommerce.feature.accounts.accounts.1b", + "ecommerce.feature.accounts.accounts.1c", + "ecommerce.feature.accounts.accounts.1d", + "ecommerce.feature.cart-checkout.cart.4a", + "ecommerce.feature.cart-checkout.cart.4d", + "ecommerce.feature.catalog.catalog-ranking.2b", + "ecommerce.feature.catalog.catalog-search.2d", + "ecommerce.feature.catalog.catalog-values.2a", + "ecommerce.feature.purchasing.purchase-order.3c", + "ecommerce.feature.reviews.reviews.6a", + "ecommerce.feature.warehouse-admin.admin-write.103a", + "ecommerce.feature.warehouse-admin.warehouse-view.7b", + "ecommerce.inventory-operations.operational-views.5c", + "ecommerce.inventory-operations.operational-views.5d", + "ecommerce.inventory-operations.operational-views.5e", + "ecommerce.inventory-operations.operational-views.5f", + "ecommerce.inventory-operations.shipping-accounting.202e", + "ecommerce.inventory-operations.stock-conservation.202a", + "ecommerce.inventory-operations.stock-conservation.202b", + "ecommerce.inventory-operations.stock-conservation.202c", + "ecommerce.inventory-operations.stock-conservation.202d", + "ecommerce.inventory-operations.warehouse-transfer.2a", + "ecommerce.l3.deferred-access.scheduled-work-access.317a", + "ecommerce.l3.deferred-durability.restart-survival.311a", + "ecommerce.l3.deferred-integrity.exactly-once.311a", + "ecommerce.l3.scheduled-restocks.scheduled-restocks.302a", + "ecommerce.l3.scheduled-restocks.scheduled-restocks.305a", + "ecommerce.l3.scheduled-restocks.scheduled-restocks.306a", + "ecommerce.l3.server-time.server-time.312a", + "ecommerce.operations-access.fulfilment-queue.1b", + "ecommerce.operations-access.fulfilment-queue.1c", + "ecommerce.operations-access.operator-authorization.201a", + "ecommerce.operations-access.operator-authorization.201c", + "ecommerce.operations-access.order-owner.204a", + "ecommerce.progression.catalog-management.catalog-management.622a", + "ecommerce.progression.catalog-management.catalog-management.622b", + "ecommerce.progression.customer-profile.customer-profile.620c", + "ecommerce.progression.faceted-search.faceted-search.401a", + "ecommerce.progression.faceted-search.faceted-search.402a", + "ecommerce.progression.managed-support.managed-support.613c", + "ecommerce.progression.notification-preferences.notification-preferences.630c", + "ecommerce.progression.promotion-rules.promotion-rule-values.620a", + "ecommerce.progression.review-access-specifications.review-eligibility-direct.618a", + "ecommerce.progression.review-access-specifications.stored-review-script.9180a", + "ecommerce.progression.staff-access.staff-access.601a", + "ecommerce.progression.staff-roles.staff-roles.621c", + "ecommerce.progression.stock-alerts.stock-alert-delivery.631c", + "ecommerce.progression.support-history.support-history.612c", + "ecommerce.progression.support-intake.support-intake.610a", + "ecommerce.progression.support-triage.support-assignment.611a", + "ecommerce.progression.support-triage.support-priority.611b", + "ecommerce.progression.support-triage.support-status.611c", + "ecommerce.returns-pricing.cancellation-and-return.3a", + "ecommerce.returns-pricing.cancellation-and-return.3b", + "ecommerce.returns-pricing.refund-accounting.203a", + "ecommerce.spec.access-control.cart-boundary.109a", + "ecommerce.spec.access-control.cart-boundary.109b", + "ecommerce.spec.access-control.customer-profile-privacy.620b", + "ecommerce.spec.access-control.fulfilment-area-boundary.1d", + "ecommerce.spec.access-control.managed-support-privacy.613b", + "ecommerce.spec.access-control.notification-preferences-privacy.630b", + "ecommerce.spec.access-control.order-ownership.106a", + "ecommerce.spec.access-control.promotion-management-boundary.620b", + "ecommerce.spec.access-control.purchase-attribution.102a", + "ecommerce.spec.access-control.purchase-session.101a", + "ecommerce.spec.access-control.review-eligibility.108a", + "ecommerce.spec.access-control.review-eligibility.108b", + "ecommerce.spec.access-control.signed-out-purchase.3a", + "ecommerce.spec.access-control.staff-area-boundary.601b", + "ecommerce.spec.access-control.staff-role-boundary.621b", + "ecommerce.spec.access-control.staff-role-revocation.621d", + "ecommerce.spec.access-control.stock-alert-privacy.631b", + "ecommerce.spec.access-control.support-history-logout.612d", + "ecommerce.spec.access-control.support-history-privacy.612b", + "ecommerce.spec.access-control.warehouse-area-boundary.7a", + "ecommerce.spec.access-control.warehouse-write-boundary.103b", + "ecommerce.spec.concurrency-safety.duplicate-checkout.203a", + "ecommerce.spec.concurrency-safety.duplicate-checkout.203b", + "ecommerce.spec.concurrency-safety.last-unit.201a", + "ecommerce.spec.concurrency-safety.last-unit.201b", + "ecommerce.spec.concurrency-safety.last-unit.201c", + "ecommerce.spec.concurrency-safety.restock-race.202a", + "ecommerce.spec.external-data-sync.external-stock.901a", + "ecommerce.spec.external-data-sync.external-stock.901c", + "ecommerce.spec.external-data-sync.external-stock.901d", + "ecommerce.spec.live-state.fulfilment-queue.1a", + "ecommerce.spec.live-state.inventory-dashboard.5a", + "ecommerce.spec.live-state.managed-support.613a", + "ecommerce.spec.live-state.open-list.902a", + "ecommerce.spec.live-state.purchase-stock.3b", + "ecommerce.spec.live-state.ranking.2c", + "ecommerce.spec.live-state.rating.6c", + "ecommerce.spec.live-state.sales-dashboard.5b", + "ecommerce.spec.live-state.shared-cart.4c", + "ecommerce.spec.live-state.stock-transfers.2b", + "ecommerce.spec.live-state.warehouse-stock.7c", + "ecommerce.spec.search-ordering.search-ordering.402b", + "ecommerce.spec.state-durability.account-state-recovery.105a", + "ecommerce.spec.state-durability.account-state-recovery.105b", + "ecommerce.spec.state-durability.cart-reload.4b", + "ecommerce.spec.state-durability.checkout-crash-durability.910b", + "ecommerce.spec.state-durability.checkout-crash-integrity.910a", + "ecommerce.spec.state-durability.customer-profile-reload.620a", + "ecommerce.spec.state-durability.notification-preferences-reload.630a", + "ecommerce.spec.state-durability.session-reload.1e", + "ecommerce.spec.state-durability.staff-role-reload.621a", + "ecommerce.spec.state-durability.support-history-reload.612a", + "ecommerce.spec.transactional-integrity.books-balance.107a", + "ecommerce.spec.transactional-integrity.books-balance.107b", + "ecommerce.spec.transactional-integrity.server-price.104a", + "ecommerce.spec.transactional-integrity.stock-alert-deduplication.631a", + "ecommerce.spec.transactional-integrity.stock-transfer-overdraw.2c", + "ecommerce.spec.transactional-integrity.unique-review.6b" + ], + "featureCatalog": { + "contentSha256": "8671f7883c2e5a24474a546ef1517407cd9334258e1a7cfe91e292a9af1952f2", + "id": "ecommerce.questlines" + }, + "diagnostic": false, + "ok": true + } +} diff --git a/tools/stack-bench/qualification-evidence/ecommerce-l3-e804c1302/current-inputs.json b/tools/stack-bench/qualification-evidence/ecommerce-l3-e804c1302/current-inputs.json new file mode 100644 index 00000000000..28866766bcd --- /dev/null +++ b/tools/stack-bench/qualification-evidence/ecommerce-l3-e804c1302/current-inputs.json @@ -0,0 +1 @@ +{"documents":{"release":{"capabilities":["backend-lifecycle","browser","concurrent-actors","database-observation","database-read","direct-database-write","direct-server-call","process-crash","request-replay"],"checkCatalog":[{"category":"feature","checkGroupId":"accounts","criterionId":"1a","description":"a visitor can create an account and is signed in as it","executionId":"selected-source-001","featureId":1,"packId":"ecommerce.feature.accounts","points":1,"role":"feature","source":"scenarios/01-account-create.json","stableKey":"ecommerce.feature.accounts.accounts.1a"},{"category":"production","checkGroupId":"accounts","criterionId":"1b","description":"a taken username is refused and does not sign the visitor in as the existing account","executionId":"selected-source-002","featureId":1,"packId":"ecommerce.feature.accounts","points":1,"role":"feature","source":"scenarios/01-account-duplicate.json","stableKey":"ecommerce.feature.accounts.accounts.1b"},{"category":"production","checkGroupId":"accounts","criterionId":"1c","description":"a wrong password is refused","executionId":"selected-source-003","featureId":1,"packId":"ecommerce.feature.accounts","points":1,"role":"feature","source":"scenarios/01-account-password.json","stableKey":"ecommerce.feature.accounts.accounts.1c"},{"category":"production","checkGroupId":"session-reload","criterionId":"1e","description":"the session survives a reload","executionId":"selected-source-004","featureId":1,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.state-durability","points":1,"requiresFeatures":["ecommerce.feature.accounts"],"role":"guarantee","source":"scenarios/01-account-reload.json","stableKey":"ecommerce.spec.state-durability.session-reload.1e"},{"category":"feature","checkGroupId":"accounts","criterionId":"1d","description":"signing out and back in returns the same account","executionId":"selected-source-005","featureId":1,"packId":"ecommerce.feature.accounts","points":1,"role":"feature","source":"scenarios/01-account-signout.json","stableKey":"ecommerce.feature.accounts.accounts.1d"},{"category":"feature","checkGroupId":"admin-write","criterionId":"103a","description":"an administrator can restock a warehouse","executionId":"selected-source-006","featureId":103,"packId":"ecommerce.feature.warehouse-admin","points":1,"role":"feature","source":"scenarios/01-admin-write-staff.json","stableKey":"ecommerce.feature.warehouse-admin.admin-write.103a"},{"category":"production","checkGroupId":"warehouse-write-boundary","criterionId":"103b","description":"the server refuses a warehouse write from staff","executionId":"selected-source-006","featureId":103,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"requiresFeatures":["ecommerce.feature.warehouse-admin"],"role":"guarantee","source":"scenarios/01-admin-write-staff.json","stableKey":"ecommerce.spec.access-control.warehouse-write-boundary.103b"},{"category":"production","checkGroupId":"purchase-stock","criterionId":"3b","description":"buying reduces the stock every other client sees, without a reload","executionId":"selected-source-007","featureId":3,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.live-state","points":2,"requiresFeatures":["ecommerce.feature.catalog-items","ecommerce.feature.purchasing"],"role":"guarantee","source":"scenarios/01-buying.json","stableKey":"ecommerce.spec.live-state.purchase-stock.3b"},{"category":"production","checkGroupId":"cart-boundary","criterionId":"109a","description":"the same cart action run by another customer changes only that customer's cart","executionId":"selected-source-008","featureId":109,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"requiresFeatures":["ecommerce.feature.cart"],"role":"guarantee","source":"scenarios/01-cart-boundary.json","stableKey":"ecommerce.spec.access-control.cart-boundary.109a"},{"category":"production","checkGroupId":"cart-boundary","criterionId":"109b","description":"a negative quantity is refused and leaves the cart unchanged","executionId":"selected-source-008","featureId":109,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":1,"requiresFeatures":["ecommerce.feature.cart"],"role":"guarantee","source":"scenarios/01-cart-boundary.json","stableKey":"ecommerce.spec.access-control.cart-boundary.109b"},{"category":"production","checkGroupId":"cart-reload","criterionId":"4b","description":"the cart survives a reload","executionId":"selected-source-009","featureId":4,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.state-durability","points":1,"requiresFeatures":["ecommerce.feature.cart"],"role":"guarantee","source":"scenarios/01-cart.json","stableKey":"ecommerce.spec.state-durability.cart-reload.4b"},{"category":"production","checkGroupId":"shared-cart","criterionId":"4c","description":"the same account signed in elsewhere sees one cart, live","executionId":"selected-source-009","featureId":4,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.live-state","points":2,"requiresFeatures":["ecommerce.feature.cart"],"role":"guarantee","source":"scenarios/01-cart.json","stableKey":"ecommerce.spec.live-state.shared-cart.4c"},{"category":"feature","checkGroupId":"catalog-ranking","criterionId":"2b","description":"the storefront shows the exact alphabetical top ten before any purchase","executionId":"selected-source-010","featureId":2,"packId":"ecommerce.feature.catalog-discovery","points":1,"role":"feature","source":"scenarios/01-catalog-ranking.json","stableKey":"ecommerce.feature.catalog.catalog-ranking.2b","stablePackId":"ecommerce.feature.catalog"},{"category":"feature","checkGroupId":"catalog-search","criterionId":"2d","description":"case-insensitive partial search finds an item outside the storefront top ten","executionId":"selected-source-011","featureId":2,"packId":"ecommerce.feature.catalog-discovery","points":1,"role":"feature","source":"scenarios/01-catalog-search.json","stableKey":"ecommerce.feature.catalog.catalog-search.2d","stablePackId":"ecommerce.feature.catalog"},{"category":"feature","checkGroupId":"catalog-values","criterionId":"2a","description":"a signed-out visitor sees the seeded item name, price, and total stock","executionId":"selected-source-012","featureId":2,"packId":"ecommerce.feature.catalog-items","points":1,"role":"feature","source":"scenarios/01-catalog-values.json","stableKey":"ecommerce.feature.catalog.catalog-values.2a","stablePackId":"ecommerce.feature.catalog"},{"category":"production","checkGroupId":"ranking","criterionId":"2c","description":"a purchase moves the bought item to the front of the ranking, live","executionId":"selected-source-013","featureId":2,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.live-state","points":1,"requiresFeatures":["ecommerce.feature.catalog-items","ecommerce.feature.purchasing"],"role":"guarantee","source":"scenarios/01-core.json","stableKey":"ecommerce.spec.live-state.ranking.2c"},{"category":"production","checkGroupId":"duplicate-checkout","criterionId":"203a","description":"the same item added from two tabs at once becomes one line of two","executionId":"selected-source-014","featureId":203,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.concurrency-safety","points":1,"requiresFeatures":["ecommerce.feature.checkout"],"role":"guarantee","source":"scenarios/01-duplicate-checkout.json","stableKey":"ecommerce.spec.concurrency-safety.duplicate-checkout.203a"},{"category":"production","checkGroupId":"duplicate-checkout","criterionId":"203b","description":"checking the same cart out twice at once produces one order","executionId":"selected-source-014","featureId":203,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.concurrency-safety","points":1,"requiresFeatures":["ecommerce.feature.checkout"],"role":"guarantee","source":"scenarios/01-duplicate-checkout.json","stableKey":"ecommerce.spec.concurrency-safety.duplicate-checkout.203b"},{"category":"production","checkGroupId":"external-stock","criterionId":"901a","description":"a direct database write sets Desk Lamp's East stock to 5, and the already-open storefront updates from 100 to 50 without a reload or page action","executionId":"selected-source-015","featureId":901,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.external-data-sync","points":1,"requiresFeatures":["ecommerce.feature.warehouse-admin"],"role":"guarantee","source":"scenarios/01-external-live-sync.json","stableKey":"ecommerce.spec.external-data-sync.external-stock.901a"},{"category":"production","checkGroupId":"external-stock","criterionId":"901d","description":"while the storefront is offline, a direct database write sets Desk Lamp's East stock to 7; after reconnecting, the same page catches up from 100 to the authoritative total of 52","executionId":"selected-source-016","featureId":901,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.external-data-sync","points":1,"requiresFeatures":["ecommerce.feature.warehouse-admin"],"role":"guarantee","source":"scenarios/01-external-reconnect-sync.json","stableKey":"ecommerce.spec.external-data-sync.external-stock.901d"},{"checkGroupId":"external-stock","criterionId":"901b","description":"after a direct database write sets Desk Lamp's East stock to 5, a reload reads the persisted total of 50","executionId":"selected-source-017","featureId":901,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.external-data-sync","points":0,"requiresFeatures":["ecommerce.feature.warehouse-admin"],"role":"guarantee","source":"scenarios/01-external-reload-sync.json","stableKey":"ecommerce.spec.external-data-sync.external-stock.901b"},{"category":"production","checkGroupId":"external-stock","criterionId":"901c","description":"a stock correction lands while the app server is stopped, and the already-open storefront shows the authoritative total of 65 after the server returns without a reload","executionId":"selected-source-018","featureId":901,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.external-data-sync","points":1,"requiresFeatures":["ecommerce.feature.warehouse-admin"],"role":"guarantee","source":"scenarios/01-external-server-restart-sync.json","stableKey":"ecommerce.spec.external-data-sync.external-stock.901c"},{"category":"production","checkGroupId":"last-unit","criterionId":"201a","description":"after six customers try to buy the last three units, each warehouse stores zero stock and all observed clients show zero stock","executionId":"selected-source-019","featureId":201,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.concurrency-safety","points":1,"requiresFeatures":["ecommerce.feature.catalog-items","ecommerce.feature.purchasing","ecommerce.feature.warehouse-admin"],"role":"guarantee","source":"scenarios/01-last-unit.json","stableKey":"ecommerce.spec.concurrency-safety.last-unit.201a"},{"category":"production","checkGroupId":"last-unit","criterionId":"201c","description":"revenue increases by exactly three sales, not six","executionId":"selected-source-019","featureId":201,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.concurrency-safety","points":1,"requiresFeatures":["ecommerce.feature.catalog-items","ecommerce.feature.purchasing","ecommerce.feature.warehouse-admin"],"role":"guarantee","source":"scenarios/01-last-unit.json","stableKey":"ecommerce.spec.concurrency-safety.last-unit.201c"},{"category":"production","checkGroupId":"last-unit","criterionId":"201b","description":"the last three units create complete orders for the successful buyers, and all four affordable purchases succeed when stock is sufficient","executionId":"selected-source-019","featureId":201,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.concurrency-safety","points":1,"requiresFeatures":["ecommerce.feature.catalog-items","ecommerce.feature.purchasing","ecommerce.feature.warehouse-admin"],"role":"guarantee","source":"scenarios/01-last-unit.json","stableKey":"ecommerce.spec.concurrency-safety.last-unit.201b"},{"category":"production","checkGroupId":"order-ownership","criterionId":"106a","description":"a working order history contains the customer's own order and not another customer's order","executionId":"selected-source-020","featureId":106,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":1,"requiresFeatures":["ecommerce.feature.purchasing"],"role":"guarantee","source":"scenarios/01-order-ownership.json","stableKey":"ecommerce.spec.access-control.order-ownership.106a"},{"category":"production","checkGroupId":"purchase-attribution","criterionId":"102a","description":"a direct purchase is attributed to the authenticated caller, not another account","executionId":"selected-source-021","featureId":102,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"requiresFeatures":["ecommerce.feature.purchasing"],"role":"guarantee","source":"scenarios/01-purchase-attribution.json","stableKey":"ecommerce.spec.access-control.purchase-attribution.102a"},{"category":"production","checkGroupId":"purchase-session","criterionId":"101a","description":"a valid direct purchase works for the buyer but is refused without a session","executionId":"selected-source-022","featureId":101,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"requiresFeatures":["ecommerce.feature.purchasing"],"role":"guarantee","source":"scenarios/01-purchase-session.json","stableKey":"ecommerce.spec.access-control.purchase-session.101a"},{"category":"feature","checkGroupId":"restock-race","criterionId":"202-control","description":"an uncontended restock of five is stored by the server and shows on the storefront","executionId":"selected-source-023","featureId":202,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.concurrency-safety","points":0,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.warehouse-admin"],"role":"guarantee","source":"scenarios/01-restock-race.json","stableKey":"ecommerce.spec.concurrency-safety.restock-race.202-control"},{"category":"production","checkGroupId":"restock-race","criterionId":"202a","description":"restocking during purchases preserves stock, complete buyer orders and their warehouse allocations","executionId":"selected-source-023","featureId":202,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.concurrency-safety","points":1,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.warehouse-admin"],"role":"guarantee","source":"scenarios/01-restock-race.json","stableKey":"ecommerce.spec.concurrency-safety.restock-race.202a"},{"category":"production","checkGroupId":"review-eligibility","criterionId":"108a","description":"someone who never bought the item cannot review it","executionId":"selected-source-024","featureId":108,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.reviews"],"role":"guarantee","source":"scenarios/01-review-eligibility.json","stableKey":"ecommerce.spec.access-control.review-eligibility.108a"},{"category":"production","checkGroupId":"review-eligibility","criterionId":"108b","description":"buying the item earns the right to review it","executionId":"selected-source-024","featureId":108,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":1,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.reviews"],"role":"guarantee","source":"scenarios/01-review-eligibility.json","stableKey":"ecommerce.spec.access-control.review-eligibility.108b"},{"category":"production","checkGroupId":"rating","criterionId":"6c","description":"the average rating reflects both reviewers and updates live","executionId":"selected-source-025","featureId":6,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.live-state","points":1,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.reviews"],"role":"guarantee","source":"scenarios/01-review-rating-live.json","stableKey":"ecommerce.spec.live-state.rating.6c"},{"category":"production","checkGroupId":"unique-review","criterionId":"6b","description":"a later review submission does not create a duplicate for the same customer and item","executionId":"selected-source-026","featureId":6,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.transactional-integrity","points":1,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.reviews"],"role":"guarantee","source":"scenarios/01-review-uniqueness.json","stableKey":"ecommerce.spec.transactional-integrity.unique-review.6b"},{"category":"feature","checkGroupId":"reviews","criterionId":"6a","description":"a customer can review an item and everyone sees it, signed out included","executionId":"selected-source-027","featureId":6,"packId":"ecommerce.feature.reviews","points":2,"role":"feature","source":"scenarios/01-review-visibility.json","stableKey":"ecommerce.feature.reviews.reviews.6a"},{"category":"production","checkGroupId":"server-price","criterionId":"104a","description":"direct purchases of two differently priced items persist exactly one correctly priced order each","executionId":"selected-source-028","featureId":104,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.transactional-integrity","points":2,"requiresFeatures":["ecommerce.feature.purchasing"],"role":"guarantee","source":"scenarios/01-server-price.json","stableKey":"ecommerce.spec.transactional-integrity.server-price.104a"},{"category":"production","checkGroupId":"warehouse-area-boundary","criterionId":"7a","description":"the administrator area stays unavailable to other staff","executionId":"selected-source-029","featureId":7,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":1,"requiresFeatures":["ecommerce.feature.warehouse-admin"],"role":"guarantee","source":"scenarios/01-warehouse-admin-staff.json","stableKey":"ecommerce.spec.access-control.warehouse-area-boundary.7a"},{"category":"feature","checkGroupId":"warehouse-view","criterionId":"7b","description":"admin lists every item, every warehouse, and what each warehouse holds","executionId":"selected-source-029","featureId":7,"packId":"ecommerce.feature.warehouse-admin","points":1,"role":"feature","source":"scenarios/01-warehouse-admin-staff.json","stableKey":"ecommerce.feature.warehouse-admin.warehouse-view.7b"},{"category":"production","checkGroupId":"warehouse-stock","criterionId":"7c","description":"the storefront stock is the sum across warehouses, and a restock raises it live","executionId":"selected-source-030","featureId":7,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.live-state","points":2,"requiresFeatures":["ecommerce.feature.catalog-items","ecommerce.feature.warehouse-admin"],"role":"guarantee","source":"scenarios/01-warehouse-stock-live-staff.json","stableKey":"ecommerce.spec.live-state.warehouse-stock.7c"},{"category":"production","checkGroupId":"cancellation-and-return","criterionId":"3d","description":"cancelling a pending order removes it from the fulfilment queue","executionId":"selected-source-031","featureId":3,"observations":["requested","unmentioned"],"packId":"ecommerce.progression.cancellation-queue-specifications","points":1,"requiresFeatures":["ecommerce.l2.order-cancellation-features","ecommerce.progression.fulfilment-queue"],"role":"guarantee","source":"scenarios/02-cancellation-queue.json","stableKey":"ecommerce.returns-pricing.cancellation-and-return.3d","stablePackId":"ecommerce.returns-pricing"},{"category":"production","checkGroupId":"fulfilment-area-boundary","criterionId":"1d","description":"staff and administrators can open fulfilment while customers cannot","executionId":"selected-source-032","featureId":1,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":1,"requiresFeatures":["ecommerce.progression.fulfilment-queue"],"role":"guarantee","source":"scenarios/02-fulfilment-access.json","stableKey":"ecommerce.spec.access-control.fulfilment-area-boundary.1d"},{"category":"production","checkGroupId":"fulfilment-queue","criterionId":"1a","description":"an order placed by a customer appears in the staff queue without a reload","executionId":"selected-source-033","featureId":1,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.live-state","points":2,"requiresFeatures":["ecommerce.progression.fulfilment-queue"],"role":"guarantee","source":"scenarios/02-fulfilment-live.json","stableKey":"ecommerce.spec.live-state.fulfilment-queue.1a"},{"category":"feature","checkGroupId":"fulfilment-queue","criterionId":"1c","description":"shipping removes the order from the queue and marks the customer's order shipped","executionId":"selected-source-034","featureId":1,"packId":"ecommerce.progression.fulfilment-queue","points":2,"requiresFeatures":["ecommerce.feature.purchasing"],"role":"feature","source":"scenarios/02-fulfilment-ship.json","stableKey":"ecommerce.operations-access.fulfilment-queue.1c","stablePackId":"ecommerce.operations-access"},{"category":"production","checkGroupId":"refund-accounting","criterionId":"203a","description":"concurrent cancellation restores original stock and the booked amount once, while revenue returns to its prior value","executionId":"selected-source-035","featureId":203,"observations":["requested","unmentioned"],"packId":"ecommerce.progression.cancellation-accounting-specifications","points":3,"requiresFeatures":["ecommerce.l2.order-cancellation-features"],"role":"guarantee","source":"scenarios/02-invariants.json","stableKey":"ecommerce.returns-pricing.refund-accounting.203a","stablePackId":"ecommerce.returns-pricing"},{"category":"production","checkGroupId":"refund-accounting","criterionId":"203b","description":"a price change does not rewrite revenue already earned","executionId":"selected-source-035","featureId":203,"observations":["requested","unmentioned"],"packId":"ecommerce.progression.price-accounting-specifications","points":2,"requiresFeatures":["ecommerce.l2.price-history-features"],"role":"guarantee","source":"scenarios/02-invariants.json","stableKey":"ecommerce.returns-pricing.refund-accounting.203b","stablePackId":"ecommerce.returns-pricing"},{"category":"production","checkGroupId":"price-history","criterionId":"4b","description":"the new price reaches a signed-out visitor without a reload","executionId":"selected-source-036","featureId":4,"packId":"ecommerce.l2.price-history-features","points":2,"role":"feature","source":"scenarios/02-live-price.json","stableKey":"ecommerce.returns-pricing.price-history.4b","stablePackId":"ecommerce.returns-pricing"},{"category":"feature","checkGroupId":"operational-views","criterionId":"5e","description":"the dashboard lists a current low-stock item","executionId":"selected-source-037","featureId":5,"packId":"ecommerce.l2.inventory-dashboard","points":1,"role":"feature","source":"scenarios/02-low-stock.json","stableKey":"ecommerce.inventory-operations.operational-views.5e","stablePackId":"ecommerce.inventory-operations"},{"category":"production","checkGroupId":"inventory-dashboard","criterionId":"5a","description":"an item falling to ten units or fewer joins the low-stock list, live","executionId":"selected-source-037","featureId":5,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.live-state","points":3,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.l2.inventory-dashboard"],"role":"guarantee","source":"scenarios/02-low-stock.json","stableKey":"ecommerce.spec.live-state.inventory-dashboard.5a"},{"category":"feature","checkGroupId":"operational-views","criterionId":"5d","description":"a signed-out visitor sees a best seller in the recommendations list","executionId":"selected-source-038","featureId":5,"packId":"ecommerce.l2.sales-dashboard","points":1,"role":"feature","source":"scenarios/02-operational-best-sellers.json","stableKey":"ecommerce.inventory-operations.operational-views.5d","stablePackId":"ecommerce.inventory-operations"},{"category":"feature","checkGroupId":"operational-views","criterionId":"5f","description":"the dashboard shows category units and revenue","executionId":"selected-source-039","featureId":5,"packId":"ecommerce.l2.sales-dashboard","points":1,"role":"feature","source":"scenarios/02-operational-category-totals.json","stableKey":"ecommerce.inventory-operations.operational-views.5f","stablePackId":"ecommerce.inventory-operations"},{"category":"production","checkGroupId":"sales-dashboard","criterionId":"5b","description":"a purchase updates that category's units and revenue live","executionId":"selected-source-039","featureId":5,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.live-state","points":3,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.l2.sales-dashboard"],"role":"guarantee","source":"scenarios/02-operational-category-totals.json","stableKey":"ecommerce.spec.live-state.sales-dashboard.5b"},{"category":"feature","checkGroupId":"operational-views","criterionId":"5c","description":"a purchase recommends another item from that category and excludes an item in the cart","executionId":"selected-source-040","featureId":5,"packId":"ecommerce.l2.recommendations","points":2,"role":"feature","source":"scenarios/02-operational-recommendations.json","stableKey":"ecommerce.inventory-operations.operational-views.5c","stablePackId":"ecommerce.inventory-operations"},{"category":"production","checkGroupId":"cancellation-and-return","criterionId":"3a","description":"cancelling a pending order restores its stock and revenue","executionId":"selected-source-041","featureId":3,"packId":"ecommerce.l2.order-cancellation-features","points":2,"role":"feature","source":"scenarios/02-order-cancellation-core.json","stableKey":"ecommerce.returns-pricing.cancellation-and-return.3a","stablePackId":"ecommerce.returns-pricing"},{"category":"feature","checkGroupId":"cancellation-and-return","criterionId":"3b","description":"a cancelled order is shown as cancelled in the customer's history","executionId":"selected-source-042","featureId":3,"packId":"ecommerce.l2.order-cancellation-features","points":1,"role":"feature","source":"scenarios/02-order-cancellation-history.json","stableKey":"ecommerce.returns-pricing.cancellation-and-return.3b","stablePackId":"ecommerce.returns-pricing"},{"category":"production","checkGroupId":"price-history","criterionId":"4a","description":"a price change updates the live catalog but leaves the customer's exact paid price unchanged","executionId":"selected-source-043","featureId":4,"observations":["requested","unmentioned"],"packId":"ecommerce.progression.price-history-specifications","points":3,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.l2.price-history-features"],"role":"guarantee","source":"scenarios/02-paid-price-history.json","stableKey":"ecommerce.returns-pricing.price-history.4a","stablePackId":"ecommerce.returns-pricing"},{"category":"feature","checkGroupId":"fulfilment-queue","criterionId":"1b","description":"the queue names the warehouse the order will ship from","executionId":"selected-source-044","featureId":1,"packId":"ecommerce.progression.fulfilment-queue","points":1,"role":"feature","source":"scenarios/02-queue-warehouse.json","stableKey":"ecommerce.operations-access.fulfilment-queue.1b","stablePackId":"ecommerce.operations-access"},{"category":"production","checkGroupId":"stock-conservation","criterionId":"202b","description":"a sale and its cancellation leave the shelf exactly as they found it","executionId":"selected-source-045","featureId":202,"observations":["requested","unmentioned"],"packId":"ecommerce.progression.inventory-conservation-specifications","points":2,"requiresFeatures":["ecommerce.l2.order-cancellation-features"],"role":"guarantee","source":"scenarios/02-self-contained.json","stableKey":"ecommerce.inventory-operations.stock-conservation.202b","stablePackId":"ecommerce.inventory-operations"},{"category":"production","checkGroupId":"stock-conservation","criterionId":"202c","description":"a fresh client sees the restored total after a sale is cancelled","executionId":"selected-source-045","featureId":202,"observations":["requested","unmentioned"],"packId":"ecommerce.progression.inventory-conservation-specifications","points":1,"requiresFeatures":["ecommerce.l2.order-cancellation-features"],"role":"guarantee","source":"scenarios/02-self-contained.json","stableKey":"ecommerce.inventory-operations.stock-conservation.202c","stablePackId":"ecommerce.inventory-operations"},{"category":"production","checkGroupId":"operator-authorization","criterionId":"201c","description":"the server refuses a customer's direct attempt to ship their own pending order","executionId":"selected-source-046","featureId":201,"observations":["requested","unmentioned"],"packId":"ecommerce.progression.operations-access-specifications","points":2,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.progression.fulfilment-queue"],"role":"guarantee","source":"scenarios/02-server-actions.json","stableKey":"ecommerce.operations-access.operator-authorization.201c","stablePackId":"ecommerce.operations-access"},{"category":"production","checkGroupId":"stock-conservation","criterionId":"202d","description":"a direct transfer racing a direct purchase leaves the exact starting total minus the sold unit","executionId":"selected-source-046","featureId":202,"observations":["requested","unmentioned"],"packId":"ecommerce.progression.inventory-conservation-specifications","points":2,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.l2.stock-transfers-features"],"role":"guarantee","source":"scenarios/02-server-actions.json","stableKey":"ecommerce.inventory-operations.stock-conservation.202d","stablePackId":"ecommerce.inventory-operations"},{"category":"production","checkGroupId":"order-owner","criterionId":"204a","description":"the server refuses one customer trying to cancel another customer's still-pending order","executionId":"selected-source-046","featureId":204,"observations":["requested","unmentioned"],"packId":"ecommerce.progression.operations-access-specifications","points":2,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.l2.order-cancellation-features"],"role":"guarantee","source":"scenarios/02-server-actions.json","stableKey":"ecommerce.operations-access.order-owner.204a","stablePackId":"ecommerce.operations-access"},{"category":"production","checkGroupId":"warehouse-transfer","criterionId":"2a","description":"a transfer decreases the source, increases the destination, and preserves the item's exact total","executionId":"selected-source-047","featureId":2,"packId":"ecommerce.l2.stock-transfers-features","points":3,"role":"feature","source":"scenarios/02-strengthened.json","stableKey":"ecommerce.inventory-operations.warehouse-transfer.2a","stablePackId":"ecommerce.inventory-operations"},{"category":"production","checkGroupId":"operator-authorization","criterionId":"201a","description":"the server refuses a customer's direct transfer and neither warehouse nor the item total changes","executionId":"selected-source-047","featureId":201,"observations":["requested","unmentioned"],"packId":"ecommerce.progression.operations-access-specifications","points":2,"requiresFeatures":["ecommerce.l2.stock-transfers-features"],"role":"guarantee","source":"scenarios/02-strengthened.json","stableKey":"ecommerce.operations-access.operator-authorization.201a","stablePackId":"ecommerce.operations-access"},{"category":"production","checkGroupId":"operator-authorization","criterionId":"201b","description":"the server refuses a customer's direct price change and the last accepted price remains exact","executionId":"selected-source-047","featureId":201,"observations":["requested","unmentioned"],"packId":"ecommerce.progression.operations-access-specifications","points":2,"requiresFeatures":["ecommerce.l2.price-history-features"],"role":"guarantee","source":"scenarios/02-strengthened.json","stableKey":"ecommerce.operations-access.operator-authorization.201b","stablePackId":"ecommerce.operations-access"},{"category":"production","checkGroupId":"stock-conservation","criterionId":"202a","description":"a transfer decreases East, increases West, and leaves the item's exact total unchanged","executionId":"selected-source-047","featureId":202,"observations":["requested","unmentioned"],"packId":"ecommerce.progression.inventory-conservation-specifications","points":2,"requiresFeatures":["ecommerce.l2.stock-transfers-features"],"role":"guarantee","source":"scenarios/02-strengthened.json","stableKey":"ecommerce.inventory-operations.stock-conservation.202a","stablePackId":"ecommerce.inventory-operations"},{"category":"production","checkGroupId":"stock-transfer-overdraw","criterionId":"2c","description":"a transfer that would overdraw a warehouse is refused and changes neither warehouse nor the item total","executionId":"selected-source-048","featureId":2,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.transactional-integrity","points":2,"requiresFeatures":["ecommerce.l2.stock-transfers-features"],"role":"guarantee","source":"scenarios/02-transfer-overdraw.json","stableKey":"ecommerce.spec.transactional-integrity.stock-transfer-overdraw.2c"},{"category":"production","checkGroupId":"stock-transfers","criterionId":"2b","description":"both warehouse totals move live and in opposite directions as stock is transferred","executionId":"selected-source-049","featureId":2,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.live-state","points":2,"requiresFeatures":["ecommerce.l2.stock-transfers-features"],"role":"guarantee","source":"scenarios/02-transfer-totals.json","stableKey":"ecommerce.spec.live-state.stock-transfers.2b"},{"category":"production","checkGroupId":"cart-expiration","criterionId":"304a","description":"an inactive cart expires without a browser, releases stock, and returns empty","executionId":"selected-source-050","featureId":304,"packId":"ecommerce.l3.cart-expiration-features","points":4,"role":"feature","source":"scenarios/03-cart-expiration.json","stableKey":"ecommerce.l3.cart-expiration.cart-expiration.304a","stablePackId":"ecommerce.l3.cart-expiration"},{"category":"production","checkGroupId":"scheduled-work-access","criterionId":"317a","description":"the server refuses customer scheduling and cancellation of restocks","executionId":"selected-source-051","featureId":317,"observations":["requested","unmentioned"],"packId":"ecommerce.l3.deferred-access-specifications","points":3,"requiresFeatures":["ecommerce.l3.scheduled-restocks-features"],"role":"guarantee","source":"scenarios/03-deferred-access.json","stableKey":"ecommerce.l3.deferred-access.scheduled-work-access.317a","stablePackId":"ecommerce.l3.deferred-access"},{"category":"production","checkGroupId":"restart-survival","criterionId":"311a","description":"a restock scheduled before restart still applies","executionId":"selected-source-052","featureId":311,"observations":["requested","unmentioned"],"packId":"ecommerce.l3.deferred-durability-specifications","points":4,"requiresFeatures":["ecommerce.l3.scheduled-restocks-features"],"role":"guarantee","source":"scenarios/03-deferred-durability.json","stableKey":"ecommerce.l3.deferred-durability.restart-survival.311a","stablePackId":"ecommerce.l3.deferred-durability"},{"category":"production","checkGroupId":"restart-survival","criterionId":"314a","description":"a reservation pending before restart still expires and returns stock","executionId":"selected-source-052","featureId":314,"observations":["requested","unmentioned"],"packId":"ecommerce.l3.deferred-durability-specifications","points":4,"requiresFeatures":["ecommerce.l3.reservations-features"],"role":"guarantee","source":"scenarios/03-deferred-durability.json","stableKey":"ecommerce.l3.deferred-durability.restart-survival.314a","stablePackId":"ecommerce.l3.deferred-durability"},{"category":"production","checkGroupId":"restart-survival","criterionId":"315a","description":"an order shipped before restart still becomes delivered","executionId":"selected-source-052","featureId":315,"observations":["requested","unmentioned"],"packId":"ecommerce.l3.deferred-durability-specifications","points":4,"requiresFeatures":["ecommerce.l3.order-delivery-features"],"role":"guarantee","source":"scenarios/03-deferred-durability.json","stableKey":"ecommerce.l3.deferred-durability.restart-survival.315a","stablePackId":"ecommerce.l3.deferred-durability"},{"category":"production","checkGroupId":"restart-survival","criterionId":"316a","description":"a cart survives restart and expires near its original five-minute deadline","executionId":"selected-source-052","featureId":316,"observations":["requested","unmentioned"],"packId":"ecommerce.l3.deferred-durability-specifications","points":4,"requiresFeatures":["ecommerce.l3.cart-expiration-features"],"role":"guarantee","source":"scenarios/03-deferred-durability.json","stableKey":"ecommerce.l3.deferred-durability.restart-survival.316a","stablePackId":"ecommerce.l3.deferred-durability"},{"category":"production","checkGroupId":"exactly-once","criterionId":"311a","description":"restart cannot replay a completed restock","executionId":"selected-source-053","featureId":311,"observations":["requested","unmentioned"],"packId":"ecommerce.l3.deferred-integrity-specifications","points":3,"requiresFeatures":["ecommerce.l3.scheduled-restocks-features"],"role":"guarantee","source":"scenarios/03-deferred-integrity.json","stableKey":"ecommerce.l3.deferred-integrity.exactly-once.311a","stablePackId":"ecommerce.l3.deferred-integrity"},{"category":"production","checkGroupId":"exactly-once","criterionId":"312a","description":"restart leaves one delivered order record","executionId":"selected-source-053","featureId":312,"observations":["requested","unmentioned"],"packId":"ecommerce.l3.deferred-integrity-specifications","points":3,"requiresFeatures":["ecommerce.l3.order-delivery-features"],"role":"guarantee","source":"scenarios/03-deferred-integrity.json","stableKey":"ecommerce.l3.deferred-integrity.exactly-once.312a","stablePackId":"ecommerce.l3.deferred-integrity"},{"category":"production","checkGroupId":"stock-conservation","criterionId":"313a","description":"expiry returns exactly the unit reserved","executionId":"selected-source-053","featureId":313,"observations":["requested","unmentioned"],"packId":"ecommerce.l3.deferred-integrity-specifications","points":3,"requiresFeatures":["ecommerce.l3.reservations-features"],"role":"guarantee","source":"scenarios/03-deferred-integrity.json","stableKey":"ecommerce.l3.deferred-integrity.stock-conservation.313a","stablePackId":"ecommerce.l3.deferred-integrity"},{"category":"production","checkGroupId":"stock-conservation","criterionId":"314a","description":"checkout does not decrement stock after the reservation already did","executionId":"selected-source-053","featureId":314,"observations":["requested","unmentioned"],"packId":"ecommerce.l3.deferred-integrity-specifications","points":3,"requiresFeatures":["ecommerce.l3.reservations-features"],"role":"guarantee","source":"scenarios/03-deferred-integrity.json","stableKey":"ecommerce.l3.deferred-integrity.stock-conservation.314a","stablePackId":"ecommerce.l3.deferred-integrity"},{"category":"production","checkGroupId":"order-delivery","criterionId":"303a","description":"a shipped order becomes delivered in customer and staff views","executionId":"selected-source-054","featureId":303,"packId":"ecommerce.l3.order-delivery-features","points":3,"role":"feature","source":"scenarios/03-order-delivery.json","stableKey":"ecommerce.l3.order-delivery.order-delivery.303a","stablePackId":"ecommerce.l3.order-delivery"},{"category":"production","checkGroupId":"order-delivery","criterionId":"305a","description":"a cancelled order remains cancelled after the delivery interval","executionId":"selected-source-054","featureId":305,"packId":"ecommerce.l3.order-delivery-features","points":2,"role":"feature","source":"scenarios/03-order-delivery.json","stableKey":"ecommerce.l3.order-delivery.order-delivery.305a","stablePackId":"ecommerce.l3.order-delivery"},{"category":"production","checkGroupId":"reservations","criterionId":"301a","description":"adding an item reserves one unit for every open viewer","executionId":"selected-source-055","featureId":301,"packId":"ecommerce.l3.reservations-features","points":2,"role":"feature","source":"scenarios/03-reservations.json","stableKey":"ecommerce.l3.reservations.reservations.301a","stablePackId":"ecommerce.l3.reservations"},{"category":"interface","checkGroupId":"reservations","criterionId":"305a","description":"the reservation timer decreases","executionId":"selected-source-055","featureId":305,"packId":"ecommerce.l3.reservations-features","points":1,"role":"feature","source":"scenarios/03-reservations.json","stableKey":"ecommerce.l3.reservations.reservations.305a","stablePackId":"ecommerce.l3.reservations"},{"category":"feature","checkGroupId":"reservations","criterionId":"306a","description":"checkout converts the reservation into an order and empties the cart","executionId":"selected-source-055","featureId":306,"packId":"ecommerce.l3.reservations-features","points":2,"role":"feature","source":"scenarios/03-reservations.json","stableKey":"ecommerce.l3.reservations.reservations.306a","stablePackId":"ecommerce.l3.reservations"},{"category":"feature","checkGroupId":"reservations","criterionId":"307a","description":"an expired reservation marks its cart line","executionId":"selected-source-055","featureId":307,"packId":"ecommerce.l3.reservations-features","points":3,"role":"feature","source":"scenarios/03-reservations.json","stableKey":"ecommerce.l3.reservations.reservations.307a","stablePackId":"ecommerce.l3.reservations"},{"category":"feature","checkGroupId":"reservations","criterionId":"308a","description":"raising quantity starts a new reservation window","executionId":"selected-source-055","featureId":308,"packId":"ecommerce.l3.reservations-features","points":2,"role":"feature","source":"scenarios/03-reservations.json","stableKey":"ecommerce.l3.reservations.reservations.308a","stablePackId":"ecommerce.l3.reservations"},{"category":"feature","checkGroupId":"scheduled-restocks","criterionId":"305a","description":"a due restock updates stock and moves to the ledger","executionId":"selected-source-056","featureId":305,"packId":"ecommerce.l3.scheduled-restocks-features","points":3,"role":"feature","source":"scenarios/03-scheduled-restock-apply.json","stableKey":"ecommerce.l3.scheduled-restocks.scheduled-restocks.305a","stablePackId":"ecommerce.l3.scheduled-restocks"},{"category":"production","checkGroupId":"scheduled-restocks","criterionId":"306a","description":"a cancelled restock never applies","executionId":"selected-source-057","featureId":306,"packId":"ecommerce.l3.scheduled-restocks-features","points":2,"role":"feature","source":"scenarios/03-scheduled-restock-cancel.json","stableKey":"ecommerce.l3.scheduled-restocks.scheduled-restocks.306a","stablePackId":"ecommerce.l3.scheduled-restocks"},{"category":"feature","checkGroupId":"scheduled-restocks","criterionId":"302a","description":"a scheduled restock is pending and its remaining time decreases","executionId":"selected-source-058","featureId":302,"packId":"ecommerce.l3.scheduled-restocks-features","points":2,"role":"feature","source":"scenarios/03-scheduled-restocks.json","stableKey":"ecommerce.l3.scheduled-restocks.scheduled-restocks.302a","stablePackId":"ecommerce.l3.scheduled-restocks"},{"category":"production","checkGroupId":"server-time","criterionId":"312a","description":"restart preserves the due time and the work later completes","executionId":"selected-source-059","featureId":312,"observations":["requested","unmentioned"],"packId":"ecommerce.l3.server-time-specifications","points":3,"requiresFeatures":["ecommerce.l3.scheduled-restocks-features"],"role":"guarantee","source":"scenarios/03-server-time.json","stableKey":"ecommerce.l3.server-time.server-time.312a","stablePackId":"ecommerce.l3.server-time"},{"category":"production","checkGroupId":"server-time","criterionId":"313a","description":"a reservation expires while its browser is closed","executionId":"selected-source-059","featureId":313,"observations":["requested","unmentioned"],"packId":"ecommerce.l3.server-time-specifications","points":3,"requiresFeatures":["ecommerce.l3.reservations-features"],"role":"guarantee","source":"scenarios/03-server-time.json","stableKey":"ecommerce.l3.server-time.server-time.313a","stablePackId":"ecommerce.l3.server-time"},{"category":"production","checkGroupId":"account-state-recovery","criterionId":"105b","description":"the same account and cart survive the connection dropping and coming back","executionId":"selected-source-060","featureId":105,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.state-durability","points":1,"requiresFeatures":["ecommerce.feature.accounts","ecommerce.feature.checkout"],"role":"guarantee","source":"scenarios/progression-account-state-reconnect.json","stableKey":"ecommerce.spec.state-durability.account-state-recovery.105b"},{"category":"production","checkGroupId":"account-state-recovery","criterionId":"105a","description":"cart and order history survive reload and backend restart, including a fresh account login","executionId":"selected-source-061","featureId":105,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.state-durability","points":1,"requiresFeatures":["ecommerce.feature.accounts","ecommerce.feature.checkout"],"role":"guarantee","source":"scenarios/progression-account-state-reload.json","stableKey":"ecommerce.spec.state-durability.account-state-recovery.105a"},{"category":"production","checkGroupId":"automatic-reorder-access","criterionId":"502c","description":"a customer cannot see or replay automatic reorder management","executionId":"selected-source-062","featureId":502,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"requiresFeatures":["ecommerce.progression.automatic-reorder"],"role":"guarantee","source":"scenarios/progression-automatic-reorder-access.json","stableKey":"ecommerce.spec.access-control.automatic-reorder-access.502c"},{"category":"production","checkGroupId":"automatic-reorder-deduplication","criterionId":"502b","description":"more sales do not duplicate a pending restock","executionId":"selected-source-063","featureId":502,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.transactional-integrity","points":2,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.progression.automatic-reorder"],"role":"guarantee","source":"scenarios/progression-automatic-reorder-duplicate.json","stableKey":"ecommerce.spec.transactional-integrity.automatic-reorder-deduplication.502b"},{"category":"feature","checkGroupId":"automatic-reorder","criterionId":"502a","description":"crossing the threshold creates one pending restock","executionId":"selected-source-064","featureId":502,"packId":"ecommerce.progression.automatic-reorder","points":3,"requiresFeatures":["ecommerce.feature.purchasing"],"role":"feature","source":"scenarios/progression-automatic-reorder.json","stableKey":"ecommerce.progression.automatic-reorder.automatic-reorder.502a"},{"category":"production","checkGroupId":"books-balance","criterionId":"107a","description":"revenue rises by exactly what was bought","executionId":"selected-source-065","featureId":107,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.transactional-integrity","points":1,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.warehouse-admin"],"role":"guarantee","source":"scenarios/progression-books-balance.json","stableKey":"ecommerce.spec.transactional-integrity.books-balance.107a"},{"category":"production","checkGroupId":"books-balance","criterionId":"107b","description":"what the store sold is what left the warehouses, and a fresh client agrees","executionId":"selected-source-065","featureId":107,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.transactional-integrity","points":1,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.warehouse-admin"],"role":"guarantee","source":"scenarios/progression-books-balance.json","stableKey":"ecommerce.spec.transactional-integrity.books-balance.107b"},{"category":"feature","checkGroupId":"bundle-checkout","criterionId":"741a","description":"adding a bundle reserves its components and checkout records the bundle price once","executionId":"selected-source-066","featureId":741,"packId":"ecommerce.feature.bundle-checkout","points":2,"role":"feature","source":"scenarios/progression-bundle-checkout.json","stableKey":"ecommerce.feature.bundle-checkout.bundle-checkout.741a"},{"category":"production","checkGroupId":"bundle-744","criterionId":"744a","description":"two competing reservations accept exactly one whole bundle without consuming extra components","executionId":"selected-source-066","featureId":744,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.bundle-integrity","points":3,"requiresFeatures":["ecommerce.feature.bundle-checkout"],"role":"guarantee","source":"scenarios/progression-bundle-checkout.json","stableKey":"ecommerce.spec.bundle-integrity.bundle-744.744a"},{"category":"production","checkGroupId":"bundle-745","criterionId":"745a","description":"a missing component refuses the reservation without taking available stock or adding a cart line","executionId":"selected-source-066","featureId":745,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.bundle-integrity","points":3,"requiresFeatures":["ecommerce.feature.bundle-checkout"],"role":"guarantee","source":"scenarios/progression-bundle-checkout.json","stableKey":"ecommerce.spec.bundle-integrity.bundle-745.745a"},{"category":"production","checkGroupId":"bundle-746","criterionId":"746a","description":"an expired reservation releases each component once across a backend restart","executionId":"selected-source-066","featureId":746,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.bundle-integrity","points":3,"requiresFeatures":["ecommerce.feature.bundle-checkout"],"role":"guarantee","source":"scenarios/progression-bundle-checkout.json","stableKey":"ecommerce.spec.bundle-integrity.bundle-746.746a"},{"category":"production","checkGroupId":"bundle-747","criterionId":"747a","description":"two checkout requests consume one reservation and create one paid bundle","executionId":"selected-source-066","featureId":747,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.bundle-integrity","points":3,"requiresFeatures":["ecommerce.feature.bundle-checkout"],"role":"guarantee","source":"scenarios/progression-bundle-checkout.json","stableKey":"ecommerce.spec.bundle-integrity.bundle-747.747a"},{"category":"feature","checkGroupId":"bundle-returns","criterionId":"742a","description":"returning a shipped bundle refunds the paid price and restores original components after its definition changes","executionId":"selected-source-067","featureId":742,"packId":"ecommerce.feature.bundle-returns","points":2,"role":"feature","source":"scenarios/progression-bundle-returns.json","stableKey":"ecommerce.feature.bundle-returns.bundle-returns.742a"},{"category":"production","checkGroupId":"bundle-742","criterionId":"742b","description":"replaying a completed bundle return after restart does not refund or restock it twice","executionId":"selected-source-067","featureId":742,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.bundle-integrity","points":3,"requiresFeatures":["ecommerce.feature.bundle-returns"],"role":"guarantee","source":"scenarios/progression-bundle-returns.json","stableKey":"ecommerce.spec.bundle-integrity.bundle-742.742b"},{"category":"production","checkGroupId":"bundle-748","criterionId":"748a","description":"another customer cannot return a paid bundle by submitting its order ID","executionId":"selected-source-067","featureId":748,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.bundle-integrity","points":3,"requiresFeatures":["ecommerce.feature.bundle-returns"],"role":"guarantee","source":"scenarios/progression-bundle-returns.json","stableKey":"ecommerce.spec.bundle-integrity.bundle-748.748a"},{"category":"feature","checkGroupId":"cart","criterionId":"4a","description":"adding the same item twice raises its quantity instead of adding a second line","executionId":"selected-source-068","featureId":4,"packId":"ecommerce.feature.cart","points":1,"role":"feature","source":"scenarios/progression-cart-checkout.json","stableKey":"ecommerce.feature.cart-checkout.cart.4a","stablePackId":"ecommerce.feature.cart-checkout"},{"category":"feature","checkGroupId":"cart","criterionId":"4d","description":"checkout creates one order, reduces stock, and empties the cart","executionId":"selected-source-068","featureId":4,"packId":"ecommerce.feature.checkout","points":2,"role":"feature","source":"scenarios/progression-cart-checkout.json","stableKey":"ecommerce.feature.cart-checkout.cart.4d","stablePackId":"ecommerce.feature.cart-checkout"},{"category":"feature","checkGroupId":"cart-recovery","criterionId":"503a","description":"restoring an expired cart reserves available items again","executionId":"selected-source-069","featureId":503,"packId":"ecommerce.progression.cart-recovery","points":3,"role":"feature","source":"scenarios/progression-cart-recovery.json","stableKey":"ecommerce.progression.cart-recovery.cart-recovery.503a"},{"category":"feature","checkGroupId":"cart-recovery","criterionId":"503b","description":"a partial restore keeps available items and names each unavailable item","executionId":"selected-source-069","featureId":503,"packId":"ecommerce.progression.cart-recovery","points":3,"role":"feature","source":"scenarios/progression-cart-recovery.json","stableKey":"ecommerce.progression.cart-recovery.cart-recovery.503b"},{"category":"feature","checkGroupId":"catalog-management","criterionId":"622a","description":"a new product reaches the public catalog","executionId":"selected-source-070","featureId":622,"packId":"ecommerce.progression.catalog-management","points":2,"role":"feature","source":"scenarios/progression-catalog-management.json","stableKey":"ecommerce.progression.catalog-management.catalog-management.622a"},{"category":"feature","checkGroupId":"catalog-management","criterionId":"622b","description":"the product exposes its named variants","executionId":"selected-source-070","featureId":622,"packId":"ecommerce.progression.catalog-management","points":2,"role":"feature","source":"scenarios/progression-catalog-management.json","stableKey":"ecommerce.progression.catalog-management.catalog-management.622b"},{"category":"production","checkGroupId":"checkout-crash-integrity","criterionId":"910a","description":"interrupted checkout recovers to the prepared cart or one complete order with the cart cleared after each independent process crash","executionId":"selected-source-071","featureId":910,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.state-durability","points":1,"requiresFeatures":["ecommerce.feature.checkout"],"role":"guarantee","source":"scenarios/progression-checkout-crash.json","stableKey":"ecommerce.spec.state-durability.checkout-crash-integrity.910a"},{"category":"production","checkGroupId":"checkout-crash-durability","criterionId":"910b","description":"acknowledged checkout is not rolled back and earlier orders remain unchanged after each independent process crash","executionId":"selected-source-071","featureId":910,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.state-durability","points":1,"requiresFeatures":["ecommerce.feature.checkout"],"role":"guarantee","source":"scenarios/progression-checkout-crash.json","stableKey":"ecommerce.spec.state-durability.checkout-crash-durability.910b"},{"category":"production","checkGroupId":"payment-records","criterionId":"623a","description":"checkout records the exact paid amount","executionId":"selected-source-072","featureId":623,"packId":"ecommerce.progression.payment-records","points":3,"role":"feature","source":"scenarios/progression-core-business.json","stableKey":"ecommerce.progression.payment-records.payment-records.623a"},{"category":"production","checkGroupId":"payment-deduplication","criterionId":"623b","description":"one checkout has one payment record","executionId":"selected-source-072","featureId":623,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.transactional-integrity","points":2,"requiresFeatures":["ecommerce.progression.payment-records"],"role":"guarantee","source":"scenarios/progression-core-business.json","stableKey":"ecommerce.spec.transactional-integrity.payment-deduplication.623b"},{"category":"feature","checkGroupId":"customer-profile","criterionId":"620c","description":"the owner can save and view a customer profile","executionId":"selected-source-073","featureId":620,"packId":"ecommerce.progression.customer-profile","points":1,"role":"feature","source":"scenarios/progression-customer-profile.json","stableKey":"ecommerce.progression.customer-profile.customer-profile.620c"},{"category":"production","checkGroupId":"customer-profile-reload","criterionId":"620a","description":"the saved profile survives reload and backend restart in a fresh browser","executionId":"selected-source-073","featureId":620,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.state-durability","points":2,"requiresFeatures":["ecommerce.progression.customer-profile"],"role":"guarantee","source":"scenarios/progression-customer-profile.json","stableKey":"ecommerce.spec.state-durability.customer-profile-reload.620a"},{"category":"production","checkGroupId":"customer-profile-privacy","criterionId":"620b","description":"another customer neither sees nor receives the owner's private address","executionId":"selected-source-073","featureId":620,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"requiresFeatures":["ecommerce.progression.customer-profile"],"role":"guarantee","source":"scenarios/progression-customer-profile.json","stableKey":"ecommerce.spec.access-control.customer-profile-privacy.620b"},{"category":"feature","checkGroupId":"delivery-notification-delivery","criterionId":"501a","description":"the order owner receives one delivery notification","executionId":"selected-source-074","featureId":501,"packId":"ecommerce.progression.delivery-notifications","points":3,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.progression.fulfilment-queue"],"role":"feature","source":"scenarios/progression-delivery-notifications.json","stableKey":"ecommerce.progression.delivery-notifications.delivery-notification-delivery.501a"},{"category":"production","checkGroupId":"delivery-notification-privacy","criterionId":"501b","description":"another customer cannot see the delivery notification","executionId":"selected-source-074","featureId":501,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.progression.delivery-notifications","ecommerce.progression.fulfilment-queue"],"role":"guarantee","source":"scenarios/progression-delivery-notifications.json","stableKey":"ecommerce.spec.access-control.delivery-notification-privacy.501b"},{"category":"feature","checkGroupId":"faceted-search","criterionId":"401a","description":"category, price, and availability filters apply together","executionId":"selected-source-075","featureId":401,"packId":"ecommerce.progression.faceted-search","points":3,"role":"feature","source":"scenarios/progression-faceted-filters.json","stableKey":"ecommerce.progression.faceted-search.faceted-search.401a"},{"category":"feature","checkGroupId":"faceted-search","criterionId":"402a","description":"moving between pages returns the same ordered items without duplicates","executionId":"selected-source-076","featureId":402,"packId":"ecommerce.progression.faceted-search","points":3,"role":"feature","source":"scenarios/progression-faceted-pagination.json","stableKey":"ecommerce.progression.faceted-search.faceted-search.402a"},{"category":"production","checkGroupId":"managed-support-privacy","criterionId":"613b","description":"another customer cannot read or reply to the managed case","executionId":"selected-source-077","featureId":613,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":1,"requiresFeatures":["ecommerce.progression.managed-support"],"role":"guarantee","source":"scenarios/progression-managed-support-privacy.json","stableKey":"ecommerce.spec.access-control.managed-support-privacy.613b"},{"category":"feature","checkGroupId":"managed-support","criterionId":"613c","description":"staff can update a support case and the customer can reply","executionId":"selected-source-078","featureId":613,"packId":"ecommerce.progression.managed-support","points":1,"role":"feature","source":"scenarios/progression-managed-support-shared.json","stableKey":"ecommerce.progression.managed-support.managed-support.613c"},{"category":"production","checkGroupId":"managed-support","criterionId":"613a","description":"the customer and staff see the same replies and status live","executionId":"selected-source-078","featureId":613,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.live-state","points":2,"requiresFeatures":["ecommerce.progression.managed-support"],"role":"guarantee","source":"scenarios/progression-managed-support-shared.json","stableKey":"ecommerce.spec.live-state.managed-support.613a"},{"category":"feature","checkGroupId":"notification-preferences","criterionId":"630c","description":"the customer can save a notification choice","executionId":"selected-source-079","featureId":630,"packId":"ecommerce.progression.notification-preferences","points":1,"role":"feature","source":"scenarios/progression-notification-preferences.json","stableKey":"ecommerce.progression.notification-preferences.notification-preferences.630c"},{"category":"production","checkGroupId":"notification-preferences-reload","criterionId":"630a","description":"notification choices survive reload and backend restart in a fresh browser","executionId":"selected-source-079","featureId":630,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.state-durability","points":2,"requiresFeatures":["ecommerce.progression.notification-preferences"],"role":"guarantee","source":"scenarios/progression-notification-preferences.json","stableKey":"ecommerce.spec.state-durability.notification-preferences-reload.630a"},{"category":"production","checkGroupId":"notification-preferences-privacy","criterionId":"630b","description":"the owner's choice does not change another account","executionId":"selected-source-079","featureId":630,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"requiresFeatures":["ecommerce.progression.notification-preferences"],"role":"guarantee","source":"scenarios/progression-notification-preferences.json","stableKey":"ecommerce.spec.access-control.notification-preferences-privacy.630b"},{"category":"production","checkGroupId":"open-list","criterionId":"902a","description":"one customer has the Keyboard's reviews open before another posts one; the already-open view shows that review exactly once","executionId":"selected-source-080","featureId":902,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.live-state","points":1,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.reviews"],"role":"guarantee","source":"scenarios/progression-open-list-live.json","stableKey":"ecommerce.spec.live-state.open-list.902a"},{"category":"interface","checkGroupId":"cancellation-and-return","criterionId":"3e","description":"a pending order does not offer a return button","executionId":"selected-source-081","featureId":331,"packId":"ecommerce.l3.order-returns-features","points":1,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.progression.fulfilment-queue"],"role":"feature","source":"scenarios/progression-order-return-boundary.json","stableKey":"ecommerce.returns-pricing.cancellation-and-return.3e","stablePackId":"ecommerce.returns-pricing"},{"category":"production","checkGroupId":"cancellation-and-return","criterionId":"3f","description":"the server refuses a pending return without changing stock or revenue","executionId":"selected-source-081","featureId":332,"packId":"ecommerce.l3.order-returns-features","points":2,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.progression.fulfilment-queue"],"role":"feature","source":"scenarios/progression-order-return-boundary.json","stableKey":"ecommerce.returns-pricing.cancellation-and-return.3f","stablePackId":"ecommerce.returns-pricing"},{"category":"production","checkGroupId":"cancellation-and-return","criterionId":"3c","description":"returning a shipped item restores stock and revenue and marks the item returned","executionId":"selected-source-082","featureId":330,"packId":"ecommerce.l3.order-returns-features","points":3,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.progression.fulfilment-queue"],"role":"feature","source":"scenarios/progression-order-return-complete.json","stableKey":"ecommerce.returns-pricing.cancellation-and-return.3c","stablePackId":"ecommerce.returns-pricing"},{"category":"production","checkGroupId":"order-support-ownership","criterionId":"614b","description":"another customer cannot attach or inspect the owner's order","executionId":"selected-source-083","featureId":614,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"requiresFeatures":["ecommerce.progression.order-support"],"role":"guarantee","source":"scenarios/progression-order-support-boundary.json","stableKey":"ecommerce.spec.access-control.order-support-ownership.614b"},{"category":"feature","checkGroupId":"order-support-owned","criterionId":"614a","description":"the customer can link their order and staff can inspect it","executionId":"selected-source-084","featureId":614,"packId":"ecommerce.progression.order-support","points":3,"role":"feature","source":"scenarios/progression-order-support-owned.json","stableKey":"ecommerce.progression.order-support.order-support-owned.614a"},{"category":"feature","checkGroupId":"personalized-recommendations","criterionId":"403a","description":"recommendations follow the customer's categories, global sales, and name tie-break","executionId":"selected-source-085","featureId":403,"packId":"ecommerce.progression.personalized-recommendations","points":4,"role":"feature","source":"scenarios/progression-personalized-recommendations.json","stableKey":"ecommerce.progression.personalized-recommendations.personalized-recommendations.403a"},{"category":"production","checkGroupId":"recommendation-profile-isolation","criterionId":"403b","description":"one customer's activity does not replace another customer's recommendations","executionId":"selected-source-085","featureId":403,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"requiresFeatures":["ecommerce.progression.personalized-recommendations"],"role":"guarantee","source":"scenarios/progression-personalized-recommendations.json","stableKey":"ecommerce.spec.access-control.recommendation-profile-isolation.403b"},{"category":"production","checkGroupId":"price-history","criterionId":"4c","description":"a price change updates an open cart and direct checkout persists the new total","executionId":"selected-source-086","featureId":420,"observations":["requested","unmentioned"],"packId":"ecommerce.progression.price-history-specifications","points":3,"requiresFeatures":["ecommerce.feature.checkout","ecommerce.l2.price-history-features"],"role":"guarantee","source":"scenarios/progression-price-cart-checkout.json","stableKey":"ecommerce.returns-pricing.price-history.4c","stablePackId":"ecommerce.returns-pricing"},{"category":"feature","checkGroupId":"product-bundles","criterionId":"740a","description":"a saved bundle shows the exact price and component quantities after reopening the application","executionId":"selected-source-087","featureId":740,"packId":"ecommerce.feature.product-bundles","points":2,"role":"feature","source":"scenarios/progression-product-bundles.json","stableKey":"ecommerce.feature.product-bundles.product-bundles.740a"},{"category":"production","checkGroupId":"bundle-743","criterionId":"743a","description":"a customer cannot replace a staff-created bundle through the application write","executionId":"selected-source-087","featureId":743,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.bundle-integrity","points":3,"requiresFeatures":["ecommerce.feature.product-bundles"],"role":"guarantee","source":"scenarios/progression-product-bundles.json","stableKey":"ecommerce.spec.bundle-integrity.bundle-743.743a"},{"category":"feature","checkGroupId":"promotion-checkout-active","criterionId":"621a","description":"an active promotion changes checkout and is recorded on the order","executionId":"selected-source-088","featureId":621,"packId":"ecommerce.progression.promotion-checkout","points":3,"role":"feature","source":"scenarios/progression-promotion-checkout.json","stableKey":"ecommerce.progression.promotion-checkout.promotion-checkout-active.621a"},{"category":"feature","checkGroupId":"promotion-checkout-expired","criterionId":"621b","description":"an expired promotion is refused","executionId":"selected-source-088","featureId":621,"packId":"ecommerce.progression.promotion-checkout","points":2,"role":"feature","source":"scenarios/progression-promotion-checkout.json","stableKey":"ecommerce.progression.promotion-checkout.promotion-checkout-expired.621b"},{"category":"feature","checkGroupId":"promotion-checkout-exhausted","criterionId":"621c","description":"a fully redeemed promotion is refused","executionId":"selected-source-088","featureId":621,"packId":"ecommerce.progression.promotion-checkout","points":2,"role":"feature","source":"scenarios/progression-promotion-checkout.json","stableKey":"ecommerce.progression.promotion-checkout.promotion-checkout-exhausted.621c"},{"category":"feature","checkGroupId":"promotion-report-redemptions","criterionId":"622a","description":"the promotion report has the exact redemption count","executionId":"selected-source-089","featureId":622,"packId":"ecommerce.progression.promotion-reporting","points":1,"role":"feature","source":"scenarios/progression-promotion-reporting.json","stableKey":"ecommerce.progression.promotion-reporting.promotion-report-redemptions.622a"},{"category":"feature","checkGroupId":"promotion-report-revenue","criterionId":"622b","description":"the promotion report has the exact discounted revenue","executionId":"selected-source-089","featureId":622,"packId":"ecommerce.progression.promotion-reporting","points":2,"role":"feature","source":"scenarios/progression-promotion-reporting.json","stableKey":"ecommerce.progression.promotion-reporting.promotion-report-revenue.622b"},{"category":"feature","checkGroupId":"promotion-rule-values","criterionId":"620a","description":"staff can save every bounded promotion value","executionId":"selected-source-090","featureId":620,"packId":"ecommerce.progression.promotion-rules","points":2,"role":"feature","source":"scenarios/progression-promotion-rules.json","stableKey":"ecommerce.progression.promotion-rules.promotion-rule-values.620a"},{"category":"production","checkGroupId":"promotion-management-boundary","criterionId":"620b","description":"customers cannot open promotion management","executionId":"selected-source-090","featureId":620,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"requiresFeatures":["ecommerce.progression.promotion-rules"],"role":"guarantee","source":"scenarios/progression-promotion-rules.json","stableKey":"ecommerce.spec.access-control.promotion-management-boundary.620b"},{"category":"feature","checkGroupId":"purchase-order","criterionId":"3c","description":"the purchase is recorded in the buyer's order history at the price paid","executionId":"selected-source-091","featureId":3,"packId":"ecommerce.feature.purchasing","points":1,"role":"feature","source":"scenarios/progression-purchasing.json","stableKey":"ecommerce.feature.purchasing.purchase-order.3c"},{"category":"feature","checkGroupId":"recommendation-feedback","criterionId":"504a","description":"dismissing a recommendation removes it from the customer view","executionId":"selected-source-092","featureId":504,"packId":"ecommerce.progression.recommendation-feedback","points":2,"role":"feature","source":"scenarios/progression-recommendation-feedback.json","stableKey":"ecommerce.progression.recommendation-feedback.recommendation-feedback.504a"},{"category":"production","checkGroupId":"recommendation-feedback-privacy","criterionId":"504b","description":"one customer's dismissal does not hide another customer's result","executionId":"selected-source-092","featureId":504,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"requiresFeatures":["ecommerce.progression.recommendation-feedback"],"role":"guarantee","source":"scenarios/progression-recommendation-feedback.json","stableKey":"ecommerce.spec.access-control.recommendation-feedback-privacy.504b"},{"category":"production","checkGroupId":"recommendation-feedback-restart","criterionId":"504c","description":"a dismissed recommendation stays absent after reload and backend restart in a fresh browser","executionId":"selected-source-092","featureId":504,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.state-durability","points":2,"requiresFeatures":["ecommerce.progression.recommendation-feedback"],"role":"guarantee","source":"scenarios/progression-recommendation-feedback.json","stableKey":"ecommerce.spec.state-durability.recommendation-feedback-restart.504c"},{"category":"production","checkGroupId":"review-eligibility-direct","criterionId":"618a","description":"a nonbuyer cannot submit or replace a review by claiming a buyer's username","executionId":"selected-source-093","featureId":618,"observations":["requested","unmentioned"],"packId":"ecommerce.progression.review-access-specifications","points":2,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.reviews"],"role":"guarantee","source":"scenarios/progression-review-access.json","stableKey":"ecommerce.progression.review-access-specifications.review-eligibility-direct.618a"},{"category":"production","checkGroupId":"stored-review-script","criterionId":"9180a","description":"review input is rejected or displayed without executing script in another customer session","executionId":"selected-source-094","featureId":9180,"observations":["unmentioned"],"packId":"ecommerce.progression.review-access-specifications","points":1,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.reviews"],"role":"guarantee","source":"scenarios/progression-review-script.json","stableKey":"ecommerce.progression.review-access-specifications.stored-review-script.9180a"},{"category":"production","checkGroupId":"search-ordering","criterionId":"402b","description":"active filters and text searches remain alphabetical after purchases; clearing them restores purchase ranking","executionId":"selected-source-095","featureId":402,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.search-ordering","points":1,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.progression.faceted-search"],"role":"guarantee","source":"scenarios/progression-search-ordering.json","stableKey":"ecommerce.spec.search-ordering.search-ordering.402b"},{"category":"production","checkGroupId":"shipping-accounting","criterionId":"202e","description":"shipping a purchased order does not deduct stock or add revenue again","executionId":"selected-source-096","featureId":202,"observations":["requested","unmentioned"],"packId":"ecommerce.progression.inventory-conservation-specifications","points":2,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.warehouse-admin","ecommerce.progression.fulfilment-queue"],"role":"guarantee","source":"scenarios/progression-shipping-accounting.json","stableKey":"ecommerce.inventory-operations.shipping-accounting.202e","stablePackId":"ecommerce.inventory-operations"},{"category":"production","checkGroupId":"signed-out-purchase","criterionId":"3a","description":"using the purchase control while signed out does not buy an item","executionId":"selected-source-097","featureId":3,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":1,"requiresFeatures":["ecommerce.feature.purchasing"],"role":"guarantee","source":"scenarios/progression-signed-out-purchase.json","stableKey":"ecommerce.spec.access-control.signed-out-purchase.3a"},{"category":"feature","checkGroupId":"split-tender-refunds-751","criterionId":"751a","description":"Full refund restores each original payment portion","executionId":"selected-source-098","featureId":751,"packId":"ecommerce.feature.split-tender-refunds","points":2,"requiresFeatures":["ecommerce.feature.split-tender-refunds","ecommerce.feature.store-credit","ecommerce.progression.support-refunds"],"role":"feature","source":"scenarios/progression-split-tender-refunds.json","stableKey":"ecommerce.feature.split-tender-refunds.split-tender-refunds-751.751a"},{"category":"production","checkGroupId":"production-756","criterionId":"756a","description":"Concurrent refunds restore the original credit and external amounts once, including after restart","executionId":"selected-source-098","featureId":756,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.split-tender-refunds","points":2,"requiresFeatures":["ecommerce.feature.split-tender-refunds","ecommerce.feature.store-credit","ecommerce.progression.support-refunds"],"role":"guarantee","source":"scenarios/progression-split-tender-refunds.json","stableKey":"ecommerce.spec.split-tender-refunds.production-756.756a"},{"category":"feature","checkGroupId":"staff-access","criterionId":"601a","description":"staff and administrators can sign in and open staff tools","executionId":"selected-source-099","featureId":601,"packId":"ecommerce.progression.staff-access","points":2,"role":"feature","source":"scenarios/progression-staff-access.json","stableKey":"ecommerce.progression.staff-access.staff-access.601a"},{"category":"production","checkGroupId":"staff-area-boundary","criterionId":"601b","description":"customers cannot open staff tools","executionId":"selected-source-099","featureId":601,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"requiresFeatures":["ecommerce.progression.staff-access"],"role":"guarantee","source":"scenarios/progression-staff-access.json","stableKey":"ecommerce.spec.access-control.staff-area-boundary.601b"},{"category":"feature","checkGroupId":"staff-activity","criterionId":"624a","description":"an administrative change records its actor, action, subject, and time","executionId":"selected-source-100","featureId":624,"packId":"ecommerce.progression.staff-activity","points":3,"role":"feature","source":"scenarios/progression-staff-activity.json","stableKey":"ecommerce.progression.staff-activity.staff-activity.624a"},{"category":"production","checkGroupId":"staff-activity-privacy","criterionId":"624b","description":"customers cannot open staff activity history","executionId":"selected-source-100","featureId":624,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"requiresFeatures":["ecommerce.progression.staff-activity"],"role":"guarantee","source":"scenarios/progression-staff-activity.json","stableKey":"ecommerce.spec.access-control.staff-activity-privacy.624b"},{"category":"feature","checkGroupId":"staff-roles","criterionId":"621c","description":"an administrator can assign a staff role","executionId":"selected-source-101","featureId":621,"packId":"ecommerce.progression.staff-roles","points":1,"role":"feature","source":"scenarios/progression-staff-roles.json","stableKey":"ecommerce.progression.staff-roles.staff-roles.621c"},{"category":"production","checkGroupId":"staff-role-reload","criterionId":"621a","description":"an assigned staff role survives reload and backend restart in a fresh browser","executionId":"selected-source-101","featureId":621,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.state-durability","points":2,"requiresFeatures":["ecommerce.progression.staff-roles"],"role":"guarantee","source":"scenarios/progression-staff-roles.json","stableKey":"ecommerce.spec.state-durability.staff-role-reload.621a"},{"category":"production","checkGroupId":"staff-role-boundary","criterionId":"621b","description":"a staff member cannot assign roles through the UI or a replayed request","executionId":"selected-source-101","featureId":621,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"requiresFeatures":["ecommerce.progression.staff-roles"],"role":"guarantee","source":"scenarios/progression-staff-roles.json","stableKey":"ecommerce.spec.access-control.staff-role-boundary.621b"},{"category":"production","checkGroupId":"staff-role-revocation","criterionId":"621d","description":"removing administrator access blocks a previously authorized session without changing the target role","executionId":"selected-source-101","featureId":621,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"requiresFeatures":["ecommerce.progression.staff-roles"],"role":"guarantee","source":"scenarios/progression-staff-roles.json","stableKey":"ecommerce.spec.access-control.staff-role-revocation.621d"},{"category":"feature","checkGroupId":"stock-alert-delivery","criterionId":"631c","description":"restored stock sends the requested alert","executionId":"selected-source-102","featureId":631,"packId":"ecommerce.progression.stock-alerts","points":1,"requiresFeatures":["ecommerce.feature.warehouse-admin"],"role":"feature","source":"scenarios/progression-stock-alert-delivery.json","stableKey":"ecommerce.progression.stock-alerts.stock-alert-delivery.631c"},{"category":"production","checkGroupId":"stock-alert-deduplication","criterionId":"631a","description":"restored stock sends one alert and later restocks do not duplicate it","executionId":"selected-source-103","featureId":631,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.transactional-integrity","points":2,"requiresFeatures":["ecommerce.feature.warehouse-admin","ecommerce.progression.stock-alerts"],"role":"guarantee","source":"scenarios/progression-stock-alerts.json","stableKey":"ecommerce.spec.transactional-integrity.stock-alert-deduplication.631a"},{"category":"production","checkGroupId":"stock-alert-privacy","criterionId":"631b","description":"a customer who did not request the alert cannot see it","executionId":"selected-source-103","featureId":631,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":1,"requiresFeatures":["ecommerce.feature.warehouse-admin","ecommerce.progression.stock-alerts"],"role":"guarantee","source":"scenarios/progression-stock-alerts.json","stableKey":"ecommerce.spec.access-control.stock-alert-privacy.631b"},{"category":"production","checkGroupId":"stock-limit","criterionId":"3d","description":"an item sells out visibly, and a further purchase is refused without changing stock","executionId":"selected-source-104","featureId":3,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.concurrency-safety","points":2,"requiresFeatures":["ecommerce.feature.purchasing"],"role":"guarantee","source":"scenarios/progression-stock-limit.json","stableKey":"ecommerce.spec.concurrency-safety.stock-limit.3d"},{"category":"feature","checkGroupId":"store-credit-750","criterionId":"750a","description":"Credit checkout records both payment portions","executionId":"selected-source-105","featureId":750,"packId":"ecommerce.feature.store-credit","points":2,"role":"feature","source":"scenarios/progression-store-credit.json","stableKey":"ecommerce.feature.store-credit.store-credit-750.750a"},{"category":"production","checkGroupId":"production-752","criterionId":"752a","description":"Repeating a grant reference does not increase the balance twice","executionId":"selected-source-105","featureId":752,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.store-credit","points":2,"requiresFeatures":["ecommerce.feature.store-credit"],"role":"guarantee","source":"scenarios/progression-store-credit.json","stableKey":"ecommerce.spec.store-credit.production-752.752a"},{"category":"production","checkGroupId":"production-753","criterionId":"753a","description":"A customer cannot grant credit","executionId":"selected-source-105","featureId":753,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.store-credit","points":2,"requiresFeatures":["ecommerce.feature.store-credit"],"role":"guarantee","source":"scenarios/progression-store-credit.json","stableKey":"ecommerce.spec.store-credit.production-753.753a"},{"category":"production","checkGroupId":"production-754","criterionId":"754a","description":"Concurrent checkout consumes one cart and one credit allocation","executionId":"selected-source-105","featureId":754,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.store-credit","points":2,"requiresFeatures":["ecommerce.feature.store-credit"],"role":"guarantee","source":"scenarios/progression-store-credit.json","stableKey":"ecommerce.spec.store-credit.production-754.754a"},{"category":"production","checkGroupId":"production-755","criterionId":"755a","description":"Issued credit survives a backend restart","executionId":"selected-source-105","featureId":755,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.store-credit","points":2,"requiresFeatures":["ecommerce.feature.store-credit"],"role":"guarantee","source":"scenarios/progression-store-credit.json","stableKey":"ecommerce.spec.store-credit.production-755.755a"},{"category":"feature","checkGroupId":"subscriptions-760","criterionId":"760a","description":"A subscription creates exactly its requested deliveries and payments","executionId":"selected-source-106","featureId":760,"packId":"ecommerce.feature.subscriptions","points":2,"role":"feature","source":"scenarios/progression-subscriptions.json","stableKey":"ecommerce.feature.subscriptions.subscriptions-760.760a"},{"category":"production","checkGroupId":"production-761","criterionId":"761a","description":"A pending subscription continues after backend restart without duplicate deliveries","executionId":"selected-source-106","featureId":761,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.subscriptions","points":2,"requiresFeatures":["ecommerce.feature.subscriptions"],"role":"guarantee","source":"scenarios/progression-subscriptions.json","stableKey":"ecommerce.spec.subscriptions.production-761.761a"},{"category":"production","checkGroupId":"production-762","criterionId":"762a","description":"Another customer cannot cancel an active subscription","executionId":"selected-source-106","featureId":762,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.subscriptions","points":2,"requiresFeatures":["ecommerce.feature.subscriptions"],"role":"guarantee","source":"scenarios/progression-subscriptions.json","stableKey":"ecommerce.spec.subscriptions.production-762.762a"},{"category":"production","checkGroupId":"production-763","criterionId":"763a","description":"Pause survives a restart and resume completes the remaining deliveries","executionId":"selected-source-106","featureId":763,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.subscriptions","points":2,"requiresFeatures":["ecommerce.feature.subscriptions"],"role":"guarantee","source":"scenarios/progression-subscriptions.json","stableKey":"ecommerce.spec.subscriptions.production-763.763a"},{"category":"feature","checkGroupId":"support-history","criterionId":"612c","description":"the customer can view their support ticket history","executionId":"selected-source-107","featureId":612,"packId":"ecommerce.progression.support-history","points":1,"role":"feature","source":"scenarios/progression-support-history.json","stableKey":"ecommerce.progression.support-history.support-history.612c"},{"category":"production","checkGroupId":"support-history-reload","criterionId":"612a","description":"support history survives reload and backend restart in a fresh browser","executionId":"selected-source-107","featureId":612,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.state-durability","points":2,"requiresFeatures":["ecommerce.progression.support-history"],"role":"guarantee","source":"scenarios/progression-support-history.json","stableKey":"ecommerce.spec.state-durability.support-history-reload.612a"},{"category":"production","checkGroupId":"support-history-privacy","criterionId":"612b","description":"another customer neither sees nor receives the private ticket","executionId":"selected-source-107","featureId":612,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"requiresFeatures":["ecommerce.progression.support-history"],"role":"guarantee","source":"scenarios/progression-support-history.json","stableKey":"ecommerce.spec.access-control.support-history-privacy.612b"},{"category":"production","checkGroupId":"support-history-logout","criterionId":"612d","description":"after logout the same browser storage no longer grants access to private support history","executionId":"selected-source-107","featureId":612,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"requiresFeatures":["ecommerce.progression.support-history"],"role":"guarantee","source":"scenarios/progression-support-history.json","stableKey":"ecommerce.spec.access-control.support-history-logout.612d"},{"category":"feature","checkGroupId":"support-intake","criterionId":"610a","description":"a visitor can submit a support ticket and receives a reference","executionId":"selected-source-108","featureId":610,"packId":"ecommerce.progression.support-intake","points":2,"role":"feature","source":"scenarios/progression-support-intake.json","stableKey":"ecommerce.progression.support-intake.support-intake.610a"},{"category":"production","checkGroupId":"support-refund-access","criterionId":"615c","description":"a customer cannot issue a refund or change its records","executionId":"selected-source-109","featureId":615,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":1,"requiresFeatures":["ecommerce.progression.support-refunds"],"role":"guarantee","source":"scenarios/progression-support-refunds-access.json","stableKey":"ecommerce.spec.access-control.support-refund-access.615c"},{"category":"production","checkGroupId":"support-refund-accounting","criterionId":"615b","description":"the refund equals the paid total, cannot be applied twice, and leaves another order unrefunded","executionId":"selected-source-110","featureId":615,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.transactional-integrity","points":1,"requiresFeatures":["ecommerce.progression.support-refunds"],"role":"guarantee","source":"scenarios/progression-support-refunds-accounting.json","stableKey":"ecommerce.spec.transactional-integrity.support-refund-accounting.615b"},{"category":"feature","checkGroupId":"support-refunds-resolution","criterionId":"615a","description":"an authorized refund resolves the case and updates the order","executionId":"selected-source-111","featureId":615,"packId":"ecommerce.progression.support-refunds","points":2,"role":"feature","source":"scenarios/progression-support-refunds-resolution.json","stableKey":"ecommerce.progression.support-refunds.support-refunds-resolution.615a"},{"category":"production","checkGroupId":"return-refund-interaction","criterionId":"757a","description":"a support refund followed by physical return restores each warehouse once and refunds only the price paid","executionId":"selected-source-112","featureId":757,"packId":"ecommerce.feature.split-tender-refunds","points":2,"requiresFeatures":["ecommerce.l3.order-returns-features","ecommerce.progression.fulfilment-queue","ecommerce.progression.support-refunds"],"role":"feature","source":"scenarios/progression-support-return-interaction.json","stableKey":"ecommerce.feature.split-tender-refunds.return-refund-interaction.757a"},{"category":"production","checkGroupId":"return-refund-interaction","criterionId":"757b","description":"a physical return followed by support refund restores each warehouse once and refunds only the price paid","executionId":"selected-source-112","featureId":757,"packId":"ecommerce.feature.split-tender-refunds","points":2,"requiresFeatures":["ecommerce.l3.order-returns-features","ecommerce.progression.fulfilment-queue","ecommerce.progression.support-refunds"],"role":"feature","source":"scenarios/progression-support-return-interaction.json","stableKey":"ecommerce.feature.split-tender-refunds.return-refund-interaction.757b"},{"category":"feature","checkGroupId":"support-assignment","criterionId":"611a","description":"staff can assign a new ticket","executionId":"selected-source-113","featureId":611,"packId":"ecommerce.progression.support-triage","points":1,"role":"feature","source":"scenarios/progression-support-triage.json","stableKey":"ecommerce.progression.support-triage.support-assignment.611a"},{"category":"feature","checkGroupId":"support-priority","criterionId":"611b","description":"staff can set a ticket priority","executionId":"selected-source-113","featureId":611,"packId":"ecommerce.progression.support-triage","points":1,"role":"feature","source":"scenarios/progression-support-triage.json","stableKey":"ecommerce.progression.support-triage.support-priority.611b"},{"category":"feature","checkGroupId":"support-status","criterionId":"611c","description":"staff can change a ticket status","executionId":"selected-source-113","featureId":611,"packId":"ecommerce.progression.support-triage","points":1,"role":"feature","source":"scenarios/progression-support-triage.json","stableKey":"ecommerce.progression.support-triage.support-status.611c"}],"components":{"fixture":{"id":"ecommerce.operations","path":"composition/fixtures/operations.json","sha256":"d06444b72dc94fe1ef5e08867d875e1f3bbaa5cd82c35a3558f399c1fcb5ceae"},"packs":[{"id":"ecommerce.feature.accounts","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/feature-accounts.json","requiresPacks":[],"sha256":"9eec7949c45ab6af816008b41245dd1e13e9164a6e10d42895eb93ad40664fbf"},{"id":"ecommerce.feature.bundle-checkout","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/feature-bundle-checkout.json","requiresPacks":["ecommerce.feature.product-bundles","ecommerce.l3.reservations-features"],"sha256":"2905f7ee7d8ae6d1086d2194649242b68ef871d10ec60e1bc0382baf5cb6e7df"},{"id":"ecommerce.feature.bundle-returns","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/feature-bundle-returns.json","requiresPacks":["ecommerce.feature.bundle-checkout","ecommerce.l3.order-returns-features"],"sha256":"c0f9424066d11efd12bf2c88ec3607ac1152ba5b1e34d7fe598529c03035e352"},{"id":"ecommerce.feature.cart","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/feature-cart.json","requiresPacks":["ecommerce.feature.accounts","ecommerce.feature.catalog-items"],"sha256":"217d2a7af92bc0551e17c12376b15668431619cc42f919f9d5a0a709f11eba78","stableId":"ecommerce.feature.cart-checkout"},{"id":"ecommerce.feature.catalog-discovery","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/feature-catalog-discovery.json","requiresPacks":["ecommerce.feature.catalog-items"],"sha256":"9aeea0db86cdacc386e5a26fed12b5604d674047c57c792e9aac3a5eabf14b42","stableId":"ecommerce.feature.catalog"},{"id":"ecommerce.feature.catalog-items","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/feature-catalog-items.json","requiresPacks":[],"sha256":"fce1929f7932d508f463793be463896fbb13ad6da2b7c57e0838188579f7a95f","stableId":"ecommerce.feature.catalog"},{"id":"ecommerce.feature.checkout","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/feature-checkout.json","requiresPacks":["ecommerce.feature.cart"],"sha256":"660aaf39db20b4fd6e405948b45f816c6733a2be37b8190b989a4d18c59eb214","stableId":"ecommerce.feature.cart-checkout"},{"id":"ecommerce.feature.product-bundles","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/feature-product-bundles.json","requiresPacks":["ecommerce.progression.catalog-management"],"sha256":"e768568827d4febae15fe2ec1d25410d86f78ada77debf9cb047d70fe3fdb12c"},{"id":"ecommerce.feature.purchasing","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/feature-purchasing.json","requiresPacks":["ecommerce.feature.accounts","ecommerce.feature.catalog-items"],"sha256":"d21746b5e7246b1771ee9f72d0cc66ef2c2cc9573485ffc839f6ca4b1b01ddff"},{"id":"ecommerce.feature.reviews","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/feature-reviews.json","requiresPacks":["ecommerce.feature.accounts","ecommerce.feature.catalog-items","ecommerce.feature.purchasing"],"sha256":"385771e4c68dbc7afbc0d68af897d698a66f744f50e4f580a813db580cf4615c"},{"id":"ecommerce.feature.split-tender-refunds","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/feature-split-tender-refunds.json","requiresPacks":["ecommerce.feature.store-credit","ecommerce.l3.order-returns-features","ecommerce.progression.support-refunds"],"sha256":"8d12162887644dc6bca1fbcccfd06ebd679bd8017b9234cc5632e6a1f508eba8"},{"id":"ecommerce.feature.store-credit","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/feature-store-credit.json","requiresPacks":["ecommerce.progression.payment-records","ecommerce.progression.staff-roles"],"sha256":"f252e74cb95d87a6a7cec629d59bc7a37cac133e6abee255738ff9a1fca50fcd"},{"id":"ecommerce.feature.subscriptions","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/feature-subscriptions.json","requiresPacks":["ecommerce.progression.payment-records"],"sha256":"31bbe7f11ac99af6eeeeadcd62c49bc635bb20384a6b5e3724b8ba9124530799"},{"id":"ecommerce.feature.warehouse-admin","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/feature-warehouse-admin.json","requiresPacks":["ecommerce.feature.catalog-items","ecommerce.progression.staff-access"],"sha256":"9230ca4ddfe048fd3903f3b90aee16a4711c6d53fbe37478917b16a6e550d66d"},{"id":"ecommerce.l2.inventory-dashboard","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/l2-inventory-dashboard.json","requiresPacks":["ecommerce.feature.warehouse-admin"],"sha256":"98d6ac14b32e61e976377df4687a13d6a780a0e96d2e49a05ce2a386e4588778","stableId":"ecommerce.inventory-operations"},{"id":"ecommerce.l2.order-cancellation-features","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/l2-order-cancellation-features.json","requiresPacks":["ecommerce.feature.purchasing","ecommerce.feature.warehouse-admin"],"sha256":"21f8663b36ea0871493903776ed32fae619183dc5fc0f74a8c1a5e8bc932f561","stableId":"ecommerce.returns-pricing"},{"id":"ecommerce.l2.price-history-features","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/l2-price-history-features.json","requiresPacks":["ecommerce.progression.catalog-management"],"sha256":"786b9f48b9670aa9cb02a439b7eda2feff11c5163a4d49939c892d604206e924","stableId":"ecommerce.returns-pricing"},{"id":"ecommerce.l2.recommendations","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/l2-recommendations.json","requiresPacks":["ecommerce.feature.cart","ecommerce.feature.purchasing"],"sha256":"a21e16ece7b0c4c6e2f0871428af4e4311ae5a91c46174a7ad644b6b93f2c18b","stableId":"ecommerce.inventory-operations"},{"id":"ecommerce.l2.sales-dashboard","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/l2-sales-dashboard.json","requiresPacks":["ecommerce.feature.purchasing"],"sha256":"5e9b1693dcea799edd672e276257a87ad6d7d88099d60be072e952e22e75ca77","stableId":"ecommerce.inventory-operations"},{"id":"ecommerce.l2.stock-transfers-features","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/l2-stock-transfers-features.json","requiresPacks":["ecommerce.feature.warehouse-admin"],"sha256":"fa9514e71b90d38623ede3aa4108cb8a53ca72ed95fc69858733ad38da7235ad","stableId":"ecommerce.inventory-operations"},{"id":"ecommerce.l3.cart-expiration-features","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/l3-cart-expiration-features.json","requiresPacks":["ecommerce.l3.reservations-features"],"sha256":"38029c5ea6d34974b155ef66c311dc500fcece1f82746cffa57ec5f0695f6a5d","stableId":"ecommerce.l3.cart-expiration"},{"id":"ecommerce.l3.deferred-access-specifications","includeRoles":["guarantee"],"moduleType":"specification","path":"composition/packs/l3-deferred-access-specifications.json","requiresPacks":[],"sha256":"cc47732a893439472253b8e209d653959966ca7be20ef0616ab24f8695096814","stableId":"ecommerce.l3.deferred-access"},{"id":"ecommerce.l3.deferred-durability-specifications","includeRoles":["guarantee"],"moduleType":"specification","path":"composition/packs/l3-deferred-durability-specifications.json","requiresPacks":[],"sha256":"9f5109ceb2a8f5e68df317910cea1911dfe79e8c42de51c83b60b760f4075d76","stableId":"ecommerce.l3.deferred-durability"},{"id":"ecommerce.l3.deferred-integrity-specifications","includeRoles":["guarantee"],"moduleType":"specification","path":"composition/packs/l3-deferred-integrity-specifications.json","requiresPacks":[],"sha256":"1a3d27f25be0b41f87afff3412b6f2c93617a68306309f471e0120d1ea359056","stableId":"ecommerce.l3.deferred-integrity"},{"id":"ecommerce.l3.order-delivery-features","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/l3-order-delivery-features.json","requiresPacks":["ecommerce.l2.order-cancellation-features","ecommerce.progression.fulfilment-queue"],"sha256":"7f86ba1b2a2791ba38ba6abeeee6078b061bdf03ea951647d79a74f6fe435b95","stableId":"ecommerce.l3.order-delivery"},{"id":"ecommerce.l3.order-returns-features","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/l3-order-returns-features.json","requiresPacks":["ecommerce.feature.warehouse-admin","ecommerce.l3.order-delivery-features"],"sha256":"cd5dc23d3c7514df91d0a54d92d97e7604e6828b1a287d0c79c714724cdc2206","stableId":"ecommerce.returns-pricing"},{"id":"ecommerce.l3.reservations-features","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/l3-reservations-features.json","requiresPacks":["ecommerce.feature.checkout","ecommerce.feature.warehouse-admin"],"sha256":"972b14948d5dea26cadab3567fc5bbd2c42d4feed5c428c004117b723acecd12","stableId":"ecommerce.l3.reservations"},{"id":"ecommerce.l3.scheduled-restocks-features","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/l3-scheduled-restocks-features.json","requiresPacks":["ecommerce.feature.warehouse-admin"],"sha256":"305c2cf78bc84c63b20cb3e5531760174355128332a365d741dbbd0d64c938cb","stableId":"ecommerce.l3.scheduled-restocks"},{"id":"ecommerce.l3.server-time-specifications","includeRoles":["guarantee"],"moduleType":"specification","path":"composition/packs/l3-server-time-specifications.json","requiresPacks":[],"sha256":"75ad830a0023bf1fe8022695f0776854d75cdbd87f5120a25312c7de33bf57c9","stableId":"ecommerce.l3.server-time"},{"id":"ecommerce.progression.automatic-reorder","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/progression-automatic-reorder.json","requiresPacks":["ecommerce.feature.purchasing","ecommerce.l3.scheduled-restocks-features","ecommerce.progression.staff-roles"],"sha256":"a1d14fcb9cd6c9e96b71d2bacdd4865badaeda913ba9cb3cb5fab8f1eb8497e7"},{"id":"ecommerce.progression.cancellation-accounting-specifications","includeRoles":["guarantee"],"moduleType":"specification","path":"composition/packs/progression-cancellation-accounting-specifications.json","requiresPacks":[],"sha256":"29b290a1356e63a9d2e937c7f92ad540403b27ebcef94df15451d12e59ac86cc","stableId":"ecommerce.returns-pricing"},{"id":"ecommerce.progression.cancellation-queue-specifications","includeRoles":["guarantee"],"moduleType":"specification","path":"composition/packs/progression-cancellation-queue-specifications.json","requiresPacks":[],"sha256":"adf9f45a20d13a400a7812fe825a73de6035f980813c19e3698128e49085b58d","stableId":"ecommerce.returns-pricing"},{"id":"ecommerce.progression.cart-recovery","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/progression-cart-recovery.json","requiresPacks":["ecommerce.l3.cart-expiration-features"],"sha256":"ca6d95040f5b81478546b9afedcc428114e795ced11b8364eb2542c258aec794"},{"id":"ecommerce.progression.catalog-management","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/progression-catalog-management.json","requiresPacks":["ecommerce.feature.catalog-discovery","ecommerce.progression.staff-roles"],"sha256":"f12e7e37d031f470683ff74671b22c1de08eb8f7fe0e9cf03cbcfb4604dd2f06"},{"id":"ecommerce.progression.customer-profile","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/progression-customer-profile.json","requiresPacks":["ecommerce.feature.accounts"],"sha256":"731eeced13c1053432560d4149d2de29fa2cd2b0051759d705cb36e92ad16bb3"},{"id":"ecommerce.progression.delivery-notifications","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/progression-delivery-notifications.json","requiresPacks":["ecommerce.l3.order-delivery-features","ecommerce.progression.notification-preferences"],"sha256":"60b58c4327d74f710f94ffc0deae1b51ef40ca1d2146e45b8e02d1b28e1146bc"},{"id":"ecommerce.progression.faceted-search","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/progression-faceted-search.json","requiresPacks":["ecommerce.feature.catalog-discovery"],"sha256":"5a967859348f967bdc43e0e2490289a859f568e4e8d809c21d5f4404d85e4dd7"},{"id":"ecommerce.progression.fulfilment-queue","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/progression-fulfilment-queue.json","requiresPacks":["ecommerce.feature.purchasing","ecommerce.feature.warehouse-admin"],"sha256":"811eeb166f261e32b5338e118b0851aa1ffeb06b3107dafb6861057e11004db4","stableId":"ecommerce.operations-access"},{"id":"ecommerce.progression.inventory-conservation-specifications","includeRoles":["guarantee"],"moduleType":"specification","path":"composition/packs/progression-inventory-conservation-specifications.json","requiresPacks":[],"sha256":"b3bff8b33e6069bf3cfd2e68389bbd50f0ec9c981d766fd2d7717dcf892463dc","stableId":"ecommerce.inventory-operations"},{"id":"ecommerce.progression.managed-support","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/progression-managed-support.json","requiresPacks":["ecommerce.progression.support-history","ecommerce.progression.support-triage"],"sha256":"6546f37be296605cad2e06bbe71d0cf014d1025a5a4b3b8997f4c38cf6329841"},{"id":"ecommerce.progression.notification-preferences","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/progression-notification-preferences.json","requiresPacks":["ecommerce.feature.accounts"],"sha256":"e8423fe1a2a615a1f2b5bd7073e9cc7040c8d2e2eadc0ef466d50e5d21aaf134"},{"id":"ecommerce.progression.operations-access-specifications","includeRoles":["guarantee"],"moduleType":"specification","path":"composition/packs/progression-operations-access-specifications.json","requiresPacks":[],"sha256":"796806b8a647fd367f53f6246d51aa998b9aa9e2a8959356d237b6411be96937","stableId":"ecommerce.operations-access"},{"id":"ecommerce.progression.order-support","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/progression-order-support.json","requiresPacks":["ecommerce.feature.purchasing","ecommerce.progression.managed-support"],"sha256":"1e1a1722adc4c72fdbf31aa34261b73975df53ffab27b28134d71b09ada1b27f"},{"id":"ecommerce.progression.payment-records","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/progression-payment-records.json","requiresPacks":["ecommerce.feature.checkout","ecommerce.feature.purchasing"],"sha256":"f9203b2def92ee787077b88ae9e31425c03cff7b43a039823c160bc69303cc3f"},{"id":"ecommerce.progression.personalized-recommendations","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/progression-personalized-recommendations.json","requiresPacks":["ecommerce.l2.recommendations"],"sha256":"fafda848a453566e61af3513659a8884979ae49218e490830774bb4c25f7b383"},{"id":"ecommerce.progression.price-accounting-specifications","includeRoles":["guarantee"],"moduleType":"specification","path":"composition/packs/progression-price-accounting-specifications.json","requiresPacks":[],"sha256":"f49fa571d5e63617537742620e92e95a9671ee87f52fd1abc15c2daaf2a6a195","stableId":"ecommerce.returns-pricing"},{"id":"ecommerce.progression.price-history-specifications","includeRoles":["guarantee"],"moduleType":"specification","path":"composition/packs/progression-price-history-specifications.json","requiresPacks":[],"sha256":"5882d2b0daee49ff6f3b8b6aace9fd63f6dca52b18f4dc72f8329e59ffcb9664","stableId":"ecommerce.returns-pricing"},{"id":"ecommerce.progression.promotion-checkout","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/progression-promotion-checkout.json","requiresPacks":["ecommerce.feature.checkout","ecommerce.progression.promotion-rules"],"sha256":"ead1c8b0ab75a29bc55eaf71ceb216f881655ce20321dc0e36ee8e72271383a9"},{"id":"ecommerce.progression.promotion-reporting","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/progression-promotion-reporting.json","requiresPacks":["ecommerce.progression.promotion-checkout"],"sha256":"a0c28a936e0929584ccf418dbbe5f53ba6b6beccd33a5a8255bbfb334a3ddca8"},{"id":"ecommerce.progression.promotion-rules","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/progression-promotion-rules.json","requiresPacks":["ecommerce.feature.catalog-items","ecommerce.progression.staff-access"],"sha256":"4275d81b85379c0030abd92208b732f616a53a2bad8054e0ee6c7f745488105c"},{"id":"ecommerce.progression.recommendation-feedback","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/progression-recommendation-feedback.json","requiresPacks":["ecommerce.progression.personalized-recommendations"],"sha256":"e7e703471cb30e8caf6acf89e3a0ad089dcde8d9320ceaf4fba7132add4007e5"},{"id":"ecommerce.progression.review-access-specifications","includeRoles":["guarantee"],"moduleType":"specification","path":"composition/packs/progression-review-access-specifications.json","requiresPacks":[],"sha256":"d89b6e559244faed30648f2ebdb462913c0b882c614ffe51821c1eb446e66d55"},{"id":"ecommerce.progression.staff-access","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/progression-staff-access.json","requiresPacks":[],"sha256":"440a036f482be11c4954abbb478693a995aea0fe0843f1959a641f3ab6733539"},{"id":"ecommerce.progression.staff-activity","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/progression-staff-activity.json","requiresPacks":["ecommerce.progression.catalog-management","ecommerce.progression.staff-roles"],"sha256":"129e48d11c4b24ae94d45350ffc93e190265dd69eb7948fc34c24c49b438db2e"},{"id":"ecommerce.progression.staff-roles","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/progression-staff-roles.json","requiresPacks":["ecommerce.progression.staff-access"],"sha256":"341efe45e33b4e2fd94a19036034963393b6f9d3749c63faf0bbff0415d0ead8"},{"id":"ecommerce.progression.stock-alerts","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/progression-stock-alerts.json","requiresPacks":["ecommerce.feature.warehouse-admin","ecommerce.progression.notification-preferences"],"sha256":"837f8fcb2c0c023704372810efdc8532246df2b795b94b8503f9d17dae415db9"},{"id":"ecommerce.progression.support-history","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/progression-support-history.json","requiresPacks":["ecommerce.feature.accounts","ecommerce.progression.support-intake"],"sha256":"23d9dd3e5132a88f3ed0d1c65afac0f6ca769f886b6fb531718831358699b90a"},{"id":"ecommerce.progression.support-intake","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/progression-support-intake.json","requiresPacks":[],"sha256":"6458979c3421deb9916903854a1889580b122813500e3437c475fd3bf73d7721"},{"id":"ecommerce.progression.support-refunds","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/progression-support-refunds.json","requiresPacks":["ecommerce.l2.order-cancellation-features","ecommerce.progression.order-support"],"sha256":"fd05f39442798d4bae9e96c65230268bd80be46f40a57007ede06d02d5a28e7c"},{"id":"ecommerce.progression.support-triage","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/progression-support-triage.json","requiresPacks":["ecommerce.progression.staff-access","ecommerce.progression.support-intake"],"sha256":"2c90c09870de8922db55a9fd8a1b07553c60fd3aebc679f3e4ff1649c752df85"},{"id":"ecommerce.spec.access-control","includeRoles":["guarantee"],"moduleType":"specification","path":"composition/packs/spec-access-control.json","requiresPacks":[],"sha256":"e8999511e92036535ee412cee4be2739aceedd565bcee9ef54c291bb0dbeaf48"},{"id":"ecommerce.spec.bundle-integrity","includeRoles":["guarantee"],"moduleType":"specification","path":"composition/packs/spec-bundle-integrity.json","requiresPacks":[],"sha256":"e0ca540f434e643c5ddbe7fb204fe1edad39376c719d48d4d544caef559595f9"},{"id":"ecommerce.spec.concurrency-safety","includeRoles":["guarantee"],"moduleType":"specification","path":"composition/packs/spec-concurrency-safety.json","requiresPacks":[],"sha256":"350390ddaf5b65e1af7e734cb69404940ec8ab7a632d7201d334a25eb06e2e4c"},{"id":"ecommerce.spec.external-data-sync","includeRoles":["guarantee"],"moduleType":"specification","path":"composition/packs/spec-external-data-sync.json","requiresPacks":[],"sha256":"f4c03de56a2e98f3d4ceb35063b9b5624f7842a4ba89915fcadd9c8a267faef2"},{"id":"ecommerce.spec.live-state","includeRoles":["guarantee"],"moduleType":"specification","path":"composition/packs/spec-live-state.json","requiresPacks":[],"sha256":"49d210d3c5a7aed24d5b296d3a63fe18e87cb9d33821c1f2cdd872a8e06e92f3"},{"id":"ecommerce.spec.search-ordering","includeRoles":["guarantee"],"moduleType":"specification","path":"composition/packs/spec-search-ordering.json","requiresPacks":[],"sha256":"f33275ca6a9593135c94170bd262203eaf65d980e6f810c393f6d07a28bffa50"},{"id":"ecommerce.spec.split-tender-refunds","includeRoles":["guarantee"],"moduleType":"specification","path":"composition/packs/spec-split-tender-refunds.json","requiresPacks":[],"sha256":"91ca0be0e80ea7d001cdd9a2959c7b2c00be3b87aeb5dc06c7db8b9d179ead8c"},{"id":"ecommerce.spec.state-durability","includeRoles":["guarantee"],"moduleType":"specification","path":"composition/packs/spec-state-durability.json","requiresPacks":[],"sha256":"df7c5808d25201493e6eafd46e37091a5f3b9d8f70f2c6ac708d59395137019d"},{"id":"ecommerce.spec.store-credit","includeRoles":["guarantee"],"moduleType":"specification","path":"composition/packs/spec-store-credit.json","requiresPacks":[],"sha256":"4d858d568aabb314ad118b3e2b5003e43710585fdbf4a85b71b9971ca636843c"},{"id":"ecommerce.spec.subscriptions","includeRoles":["guarantee"],"moduleType":"specification","path":"composition/packs/spec-subscriptions.json","requiresPacks":[],"sha256":"7dac820cfeec043b619d468be0c6b0d7e022093851e7884ad573a80aeeb468f2"},{"id":"ecommerce.spec.transactional-integrity","includeRoles":["guarantee"],"moduleType":"specification","path":"composition/packs/spec-transactional-integrity.json","requiresPacks":[],"sha256":"3894b3d9967c3cbb65ea3a3d5b0f8eb88f2673c06b9122f75acc945c8ca06f5f"}]},"contentSha256":"53fbb8093b2335837d88c246f04da99858c40b57ce24d17fbd2b6c815abdb62d","executionSha256":"558ea7e4033dd1e08c76c2ecc475751f2cabd210f4e18cc0f2c6e3e3531a2498","id":"ecommerce.progression-catalog","meaningSha256":"79dc9a2f8ee5854d3f4edf68862942778d0fa0bd667b35554f065d025726aa76","recipeReleaseSchemaVersion":3,"scoring":{"checks":190,"mode":"source-points","points":359},"sequence":null,"sourceManifest":[{"kinds":["fixture"],"path":"composition/fixtures/operations.json","sha256":"d06444b72dc94fe1ef5e08867d875e1f3bbaa5cd82c35a3558f399c1fcb5ceae"},{"kinds":["pack"],"path":"composition/packs/feature-accounts.json","sha256":"9eec7949c45ab6af816008b41245dd1e13e9164a6e10d42895eb93ad40664fbf"},{"kinds":["pack"],"path":"composition/packs/feature-bundle-checkout.json","sha256":"2905f7ee7d8ae6d1086d2194649242b68ef871d10ec60e1bc0382baf5cb6e7df"},{"kinds":["pack"],"path":"composition/packs/feature-bundle-returns.json","sha256":"c0f9424066d11efd12bf2c88ec3607ac1152ba5b1e34d7fe598529c03035e352"},{"kinds":["pack"],"path":"composition/packs/feature-cart.json","sha256":"217d2a7af92bc0551e17c12376b15668431619cc42f919f9d5a0a709f11eba78"},{"kinds":["pack"],"path":"composition/packs/feature-catalog-discovery.json","sha256":"9aeea0db86cdacc386e5a26fed12b5604d674047c57c792e9aac3a5eabf14b42"},{"kinds":["pack"],"path":"composition/packs/feature-catalog-items.json","sha256":"fce1929f7932d508f463793be463896fbb13ad6da2b7c57e0838188579f7a95f"},{"kinds":["pack"],"path":"composition/packs/feature-checkout.json","sha256":"660aaf39db20b4fd6e405948b45f816c6733a2be37b8190b989a4d18c59eb214"},{"kinds":["pack"],"path":"composition/packs/feature-product-bundles.json","sha256":"e768568827d4febae15fe2ec1d25410d86f78ada77debf9cb047d70fe3fdb12c"},{"kinds":["pack"],"path":"composition/packs/feature-purchasing.json","sha256":"d21746b5e7246b1771ee9f72d0cc66ef2c2cc9573485ffc839f6ca4b1b01ddff"},{"kinds":["pack"],"path":"composition/packs/feature-reviews.json","sha256":"385771e4c68dbc7afbc0d68af897d698a66f744f50e4f580a813db580cf4615c"},{"kinds":["pack"],"path":"composition/packs/feature-split-tender-refunds.json","sha256":"8d12162887644dc6bca1fbcccfd06ebd679bd8017b9234cc5632e6a1f508eba8"},{"kinds":["pack"],"path":"composition/packs/feature-store-credit.json","sha256":"f252e74cb95d87a6a7cec629d59bc7a37cac133e6abee255738ff9a1fca50fcd"},{"kinds":["pack"],"path":"composition/packs/feature-subscriptions.json","sha256":"31bbe7f11ac99af6eeeeadcd62c49bc635bb20384a6b5e3724b8ba9124530799"},{"kinds":["pack"],"path":"composition/packs/feature-warehouse-admin.json","sha256":"9230ca4ddfe048fd3903f3b90aee16a4711c6d53fbe37478917b16a6e550d66d"},{"kinds":["pack"],"path":"composition/packs/l2-inventory-dashboard.json","sha256":"98d6ac14b32e61e976377df4687a13d6a780a0e96d2e49a05ce2a386e4588778"},{"kinds":["pack"],"path":"composition/packs/l2-order-cancellation-features.json","sha256":"21f8663b36ea0871493903776ed32fae619183dc5fc0f74a8c1a5e8bc932f561"},{"kinds":["pack"],"path":"composition/packs/l2-price-history-features.json","sha256":"786b9f48b9670aa9cb02a439b7eda2feff11c5163a4d49939c892d604206e924"},{"kinds":["pack"],"path":"composition/packs/l2-recommendations.json","sha256":"a21e16ece7b0c4c6e2f0871428af4e4311ae5a91c46174a7ad644b6b93f2c18b"},{"kinds":["pack"],"path":"composition/packs/l2-sales-dashboard.json","sha256":"5e9b1693dcea799edd672e276257a87ad6d7d88099d60be072e952e22e75ca77"},{"kinds":["pack"],"path":"composition/packs/l2-stock-transfers-features.json","sha256":"fa9514e71b90d38623ede3aa4108cb8a53ca72ed95fc69858733ad38da7235ad"},{"kinds":["pack"],"path":"composition/packs/l3-cart-expiration-features.json","sha256":"38029c5ea6d34974b155ef66c311dc500fcece1f82746cffa57ec5f0695f6a5d"},{"kinds":["pack"],"path":"composition/packs/l3-deferred-access-specifications.json","sha256":"cc47732a893439472253b8e209d653959966ca7be20ef0616ab24f8695096814"},{"kinds":["pack"],"path":"composition/packs/l3-deferred-durability-specifications.json","sha256":"9f5109ceb2a8f5e68df317910cea1911dfe79e8c42de51c83b60b760f4075d76"},{"kinds":["pack"],"path":"composition/packs/l3-deferred-integrity-specifications.json","sha256":"1a3d27f25be0b41f87afff3412b6f2c93617a68306309f471e0120d1ea359056"},{"kinds":["pack"],"path":"composition/packs/l3-order-delivery-features.json","sha256":"7f86ba1b2a2791ba38ba6abeeee6078b061bdf03ea951647d79a74f6fe435b95"},{"kinds":["pack"],"path":"composition/packs/l3-order-returns-features.json","sha256":"cd5dc23d3c7514df91d0a54d92d97e7604e6828b1a287d0c79c714724cdc2206"},{"kinds":["pack"],"path":"composition/packs/l3-reservations-features.json","sha256":"972b14948d5dea26cadab3567fc5bbd2c42d4feed5c428c004117b723acecd12"},{"kinds":["pack"],"path":"composition/packs/l3-scheduled-restocks-features.json","sha256":"305c2cf78bc84c63b20cb3e5531760174355128332a365d741dbbd0d64c938cb"},{"kinds":["pack"],"path":"composition/packs/l3-server-time-specifications.json","sha256":"75ad830a0023bf1fe8022695f0776854d75cdbd87f5120a25312c7de33bf57c9"},{"kinds":["pack"],"path":"composition/packs/progression-automatic-reorder.json","sha256":"a1d14fcb9cd6c9e96b71d2bacdd4865badaeda913ba9cb3cb5fab8f1eb8497e7"},{"kinds":["pack"],"path":"composition/packs/progression-cancellation-accounting-specifications.json","sha256":"29b290a1356e63a9d2e937c7f92ad540403b27ebcef94df15451d12e59ac86cc"},{"kinds":["pack"],"path":"composition/packs/progression-cancellation-queue-specifications.json","sha256":"adf9f45a20d13a400a7812fe825a73de6035f980813c19e3698128e49085b58d"},{"kinds":["pack"],"path":"composition/packs/progression-cart-recovery.json","sha256":"ca6d95040f5b81478546b9afedcc428114e795ced11b8364eb2542c258aec794"},{"kinds":["pack"],"path":"composition/packs/progression-catalog-management.json","sha256":"f12e7e37d031f470683ff74671b22c1de08eb8f7fe0e9cf03cbcfb4604dd2f06"},{"kinds":["pack"],"path":"composition/packs/progression-customer-profile.json","sha256":"731eeced13c1053432560d4149d2de29fa2cd2b0051759d705cb36e92ad16bb3"},{"kinds":["pack"],"path":"composition/packs/progression-delivery-notifications.json","sha256":"60b58c4327d74f710f94ffc0deae1b51ef40ca1d2146e45b8e02d1b28e1146bc"},{"kinds":["pack"],"path":"composition/packs/progression-faceted-search.json","sha256":"5a967859348f967bdc43e0e2490289a859f568e4e8d809c21d5f4404d85e4dd7"},{"kinds":["pack"],"path":"composition/packs/progression-fulfilment-queue.json","sha256":"811eeb166f261e32b5338e118b0851aa1ffeb06b3107dafb6861057e11004db4"},{"kinds":["pack"],"path":"composition/packs/progression-inventory-conservation-specifications.json","sha256":"b3bff8b33e6069bf3cfd2e68389bbd50f0ec9c981d766fd2d7717dcf892463dc"},{"kinds":["pack"],"path":"composition/packs/progression-managed-support.json","sha256":"6546f37be296605cad2e06bbe71d0cf014d1025a5a4b3b8997f4c38cf6329841"},{"kinds":["pack"],"path":"composition/packs/progression-notification-preferences.json","sha256":"e8423fe1a2a615a1f2b5bd7073e9cc7040c8d2e2eadc0ef466d50e5d21aaf134"},{"kinds":["pack"],"path":"composition/packs/progression-operations-access-specifications.json","sha256":"796806b8a647fd367f53f6246d51aa998b9aa9e2a8959356d237b6411be96937"},{"kinds":["pack"],"path":"composition/packs/progression-order-support.json","sha256":"1e1a1722adc4c72fdbf31aa34261b73975df53ffab27b28134d71b09ada1b27f"},{"kinds":["pack"],"path":"composition/packs/progression-payment-records.json","sha256":"f9203b2def92ee787077b88ae9e31425c03cff7b43a039823c160bc69303cc3f"},{"kinds":["pack"],"path":"composition/packs/progression-personalized-recommendations.json","sha256":"fafda848a453566e61af3513659a8884979ae49218e490830774bb4c25f7b383"},{"kinds":["pack"],"path":"composition/packs/progression-price-accounting-specifications.json","sha256":"f49fa571d5e63617537742620e92e95a9671ee87f52fd1abc15c2daaf2a6a195"},{"kinds":["pack"],"path":"composition/packs/progression-price-history-specifications.json","sha256":"5882d2b0daee49ff6f3b8b6aace9fd63f6dca52b18f4dc72f8329e59ffcb9664"},{"kinds":["pack"],"path":"composition/packs/progression-promotion-checkout.json","sha256":"ead1c8b0ab75a29bc55eaf71ceb216f881655ce20321dc0e36ee8e72271383a9"},{"kinds":["pack"],"path":"composition/packs/progression-promotion-reporting.json","sha256":"a0c28a936e0929584ccf418dbbe5f53ba6b6beccd33a5a8255bbfb334a3ddca8"},{"kinds":["pack"],"path":"composition/packs/progression-promotion-rules.json","sha256":"4275d81b85379c0030abd92208b732f616a53a2bad8054e0ee6c7f745488105c"},{"kinds":["pack"],"path":"composition/packs/progression-recommendation-feedback.json","sha256":"e7e703471cb30e8caf6acf89e3a0ad089dcde8d9320ceaf4fba7132add4007e5"},{"kinds":["pack"],"path":"composition/packs/progression-review-access-specifications.json","sha256":"d89b6e559244faed30648f2ebdb462913c0b882c614ffe51821c1eb446e66d55"},{"kinds":["pack"],"path":"composition/packs/progression-staff-access.json","sha256":"440a036f482be11c4954abbb478693a995aea0fe0843f1959a641f3ab6733539"},{"kinds":["pack"],"path":"composition/packs/progression-staff-activity.json","sha256":"129e48d11c4b24ae94d45350ffc93e190265dd69eb7948fc34c24c49b438db2e"},{"kinds":["pack"],"path":"composition/packs/progression-staff-roles.json","sha256":"341efe45e33b4e2fd94a19036034963393b6f9d3749c63faf0bbff0415d0ead8"},{"kinds":["pack"],"path":"composition/packs/progression-stock-alerts.json","sha256":"837f8fcb2c0c023704372810efdc8532246df2b795b94b8503f9d17dae415db9"},{"kinds":["pack"],"path":"composition/packs/progression-support-history.json","sha256":"23d9dd3e5132a88f3ed0d1c65afac0f6ca769f886b6fb531718831358699b90a"},{"kinds":["pack"],"path":"composition/packs/progression-support-intake.json","sha256":"6458979c3421deb9916903854a1889580b122813500e3437c475fd3bf73d7721"},{"kinds":["pack"],"path":"composition/packs/progression-support-refunds.json","sha256":"fd05f39442798d4bae9e96c65230268bd80be46f40a57007ede06d02d5a28e7c"},{"kinds":["pack"],"path":"composition/packs/progression-support-triage.json","sha256":"2c90c09870de8922db55a9fd8a1b07553c60fd3aebc679f3e4ff1649c752df85"},{"kinds":["pack"],"path":"composition/packs/spec-access-control.json","sha256":"e8999511e92036535ee412cee4be2739aceedd565bcee9ef54c291bb0dbeaf48"},{"kinds":["pack"],"path":"composition/packs/spec-bundle-integrity.json","sha256":"e0ca540f434e643c5ddbe7fb204fe1edad39376c719d48d4d544caef559595f9"},{"kinds":["pack"],"path":"composition/packs/spec-concurrency-safety.json","sha256":"350390ddaf5b65e1af7e734cb69404940ec8ab7a632d7201d334a25eb06e2e4c"},{"kinds":["pack"],"path":"composition/packs/spec-external-data-sync.json","sha256":"f4c03de56a2e98f3d4ceb35063b9b5624f7842a4ba89915fcadd9c8a267faef2"},{"kinds":["pack"],"path":"composition/packs/spec-live-state.json","sha256":"49d210d3c5a7aed24d5b296d3a63fe18e87cb9d33821c1f2cdd872a8e06e92f3"},{"kinds":["pack"],"path":"composition/packs/spec-search-ordering.json","sha256":"f33275ca6a9593135c94170bd262203eaf65d980e6f810c393f6d07a28bffa50"},{"kinds":["pack"],"path":"composition/packs/spec-split-tender-refunds.json","sha256":"91ca0be0e80ea7d001cdd9a2959c7b2c00be3b87aeb5dc06c7db8b9d179ead8c"},{"kinds":["pack"],"path":"composition/packs/spec-state-durability.json","sha256":"df7c5808d25201493e6eafd46e37091a5f3b9d8f70f2c6ac708d59395137019d"},{"kinds":["pack"],"path":"composition/packs/spec-store-credit.json","sha256":"4d858d568aabb314ad118b3e2b5003e43710585fdbf4a85b71b9971ca636843c"},{"kinds":["pack"],"path":"composition/packs/spec-subscriptions.json","sha256":"7dac820cfeec043b619d468be0c6b0d7e022093851e7884ad573a80aeeb468f2"},{"kinds":["pack"],"path":"composition/packs/spec-transactional-integrity.json","sha256":"3894b3d9967c3cbb65ea3a3d5b0f8eb88f2673c06b9122f75acc945c8ca06f5f"},{"kinds":["recipe"],"path":"composition/recipes/progression-catalog.json","sha256":"a869c95b1d5a222dc679d1529a789d623be3d0a82beff818e6b94702a1791ee9"},{"kinds":["contract-source"],"path":"contracts/accounts.md","sha256":"19b453ded62710d998bce1b169497342209feefccd9c4b1cef3bbb9442f01488"},{"kinds":["contract-source"],"path":"contracts/application-interface.md","sha256":"b770db6c1dbf92c106c7501a17028876a30a63655c8f88b5667b44557f401692"},{"kinds":["contract-source"],"path":"contracts/bundle-checkout.md","sha256":"2c4e70b620934dc927ad4c84c17e54b6e9cef665ba3b098f9f2fc9e79a3c4c3e"},{"kinds":["contract-source"],"path":"contracts/bundle-returns.md","sha256":"69f8bf6afc325a98bab38235e49eaa2875bc674e6a61c7559692593018c9f527"},{"kinds":["contract-source"],"path":"contracts/cart-expiration.md","sha256":"56c0966494cd19b629140f8b8d53e8b9838e34668a5cab6b7cccb41b78734c50"},{"kinds":["contract-source"],"path":"contracts/cart.md","sha256":"bb1b8741b9eb47b5766a330bb1fc23005f7540fdc79d20efdaefb183cf50918d"},{"kinds":["contract-source"],"path":"contracts/catalog-discovery.md","sha256":"d13ea495f78e3827b7a243b97466aefbf0252980c76edb432b6b0506854e8450"},{"kinds":["contract-source"],"path":"contracts/catalog-items.md","sha256":"596ec08b1f4a6b290595570f3bcf2847a1f60feeb20d90f98d25761666bfe9f2"},{"kinds":["contract-source"],"path":"contracts/catalog-management.md","sha256":"5123971185ded331deaef2e323fad31e6133d55fc839289e2c4a0dfc5292ee4e"},{"kinds":["contract-source"],"path":"contracts/checkout.md","sha256":"49416683e06d996a28980ff650a3281f89cae062269b7de761899e71759c731c"},{"kinds":["contract-source"],"path":"contracts/customer-profile.md","sha256":"7451bf14ada950c9b7ad269d63467154c388e9ea18b97f479037cdd397ca519f"},{"kinds":["contract-source"],"path":"contracts/delivery-notifications.md","sha256":"4bf565ea751bb5278bae5910420beeb531a2eb88fb5755e5a06dda68860af490"},{"kinds":["contract-source"],"path":"contracts/faceted-search.md","sha256":"08ace4d2d1947f16ceb4da95e6993086c9bd77a0977c258fef1f0a96c7e7879d"},{"kinds":["contract-source"],"path":"contracts/inventory-dashboard.md","sha256":"8c3de4ff8a958776ca087febbbbf5f950eaef9efacb96b7c4fa49357b2d0a371"},{"kinds":["contract-source"],"path":"contracts/managed-support.md","sha256":"458b89a7f786086a95957c778943660068cd6c00b30635fd1cd786c37df76398"},{"kinds":["contract-source"],"path":"contracts/notification-preferences.md","sha256":"d6b4231f67d5e70a03ec331545b6419acf766b52841c8520b94963c16aa13fec"},{"kinds":["contract-source"],"path":"contracts/operations-access.md","sha256":"fd9c31482b484dc1f9bf3c521d247971334e1f52f51a7548a987bdebc65dbdb5"},{"kinds":["contract-source"],"path":"contracts/order-cancellation.md","sha256":"fc274b1409c50de8edcf797ab83cf8e8c46a54db30ada859f854e1cd40c7dee1"},{"kinds":["contract-source"],"path":"contracts/order-data.md","sha256":"7b7cfc6b102f4836235c7f23344865f60156b3e4ac96c3e5cbb0e298390b3b06"},{"kinds":["contract-source"],"path":"contracts/order-delivery.md","sha256":"74bd21b39c8d5f020ff62cc408992c15788e48eba8e05a76a0cddc4b4920a98e"},{"kinds":["contract-source"],"path":"contracts/order-returns.md","sha256":"fe0668ab3bf00d4c167794dbecb75b26b23cb62dfc0a1b79636a013edb237329"},{"kinds":["contract-source"],"path":"contracts/order-support.md","sha256":"a2901e66af870055b6c3c26f240132ae08f3cb93d0c52a7b2573c9dc153e1e03"},{"kinds":["contract-source"],"path":"contracts/payment-records.md","sha256":"8c752352c7f47a0a65d1823f9ec74009dc95088fc6c2a6cc30d1a1dc7fa11fe0"},{"kinds":["contract-source"],"path":"contracts/price-history-orders.md","sha256":"c3a86a7de94e345c578d6b9ba3527c82c137797f385ca4aca3cf2b7ee39b9d40"},{"kinds":["contract-source"],"path":"contracts/price-history.md","sha256":"3465714f91e0e978607900b19377a134e9beb704848e2462b1438465cc2e98ee"},{"kinds":["contract-source"],"path":"contracts/product-bundles.md","sha256":"b27905002b693e6c63532cd8193c8e3fd1fdeaad85041d84b8240a2092bf1c57"},{"kinds":["contract-source"],"path":"contracts/progression-automatic-reorder.md","sha256":"3e70361965e6ddeb7b05cc7ad5348e363d58d628734de96b8a9792e68e71cc72"},{"kinds":["contract-source"],"path":"contracts/progression-cart-recovery.md","sha256":"daf04aea3082483caa2ebf3a3c89a438329600cb6aa5d74fb47d97bc244e5747"},{"kinds":["contract-source"],"path":"contracts/progression-personalized-recommendations.md","sha256":"42389a6d284dcfdb53a610ce5ce77d40dbc2b9d5e177bbd3f6bccc40079c7d98"},{"kinds":["contract-source"],"path":"contracts/promotion-checkout.md","sha256":"b74e703dc77c9eeec26f5beb41cab102570c8314d817015c858557e9946293aa"},{"kinds":["contract-source"],"path":"contracts/promotion-reporting.md","sha256":"81cded5fd9a8822c8756ea50bedb879971c94f8727d176f22fa53d2a6a1efbb0"},{"kinds":["contract-source"],"path":"contracts/promotion-rules.md","sha256":"f352f8bb938aa874125b10bbb6182643f04b6d1ce82cde41512bd16835a7b90b"},{"kinds":["contract-source"],"path":"contracts/purchasing.md","sha256":"c2d59da67b400d055ab90bf53f2e46a3af9605a1fc68534c2b64d8db2ed3409c"},{"kinds":["contract-source"],"path":"contracts/recommendation-feedback.md","sha256":"00a96f594c8da1ffb4a933c6f8d8d0219216ab6cc2c781cfd17dd9c97c517d58"},{"kinds":["contract-source"],"path":"contracts/recommendations.md","sha256":"ab5417cbf78f43464e82a543e50e9601580bb2b3a57826a9e73da9899f39de16"},{"kinds":["contract-source"],"path":"contracts/reservations.md","sha256":"e1c4af7a67dd200d5f18d550e5b4c30e7a4bbaf60600b434108ebff7bdf90627"},{"kinds":["contract-source"],"path":"contracts/reviews.md","sha256":"6be3567258c0c4bf3331e609f63be26ad0bb43ceca3e7da4accaaad8c9ac6541"},{"kinds":["contract-source"],"path":"contracts/sales-dashboard.md","sha256":"ff9ed3890aa5c8303a0badecf946e7d98da3fbbb0a2890a693099bab1a2056c0"},{"kinds":["contract-source"],"path":"contracts/scheduled-restocks.md","sha256":"a946c0954a641d4fe64b933761e2b92d546ae08ee434d676c6faed3ed8b03c8e"},{"kinds":["contract-source"],"path":"contracts/split-tender-refunds.md","sha256":"62b8b3c233d33858e9b696d06d94c70f6524f8cbed77028acc0d2affdd780841"},{"kinds":["contract-source"],"path":"contracts/staff-access.md","sha256":"dcd7b740d5f65160ddf0b4221d29f84426ee89f04560e953add0856cf0bca87a"},{"kinds":["contract-source"],"path":"contracts/staff-activity.md","sha256":"7e7c1846445f82aa78ad8e32606e6830f9d326ebfea75d13b077c073695c9594"},{"kinds":["contract-source"],"path":"contracts/staff-roles.md","sha256":"cce6145182485fafcd2adc29cec90af20523a2afd9c952800eefb5d15a49f96e"},{"kinds":["contract-source"],"path":"contracts/stock-alerts.md","sha256":"405f106569c84b3062f8159452730f16adadf12d804c554a570e39b958b63421"},{"kinds":["contract-source"],"path":"contracts/stock-transfers.md","sha256":"01f28ebb3487559d4689919f0991e43f74fcc85609fa4c810e92adde30e84096"},{"kinds":["contract-source"],"path":"contracts/store-credit.md","sha256":"505ca48dfc4f9f2d6ea38e53e1bd382910264d0195be8580b5fb01f7e7074713"},{"kinds":["contract-source"],"path":"contracts/subscriptions.md","sha256":"dc533bc7f3b9be03ae7d9e18c2e02ffa996bf934b9ba230826d492b4cefa045e"},{"kinds":["contract-source"],"path":"contracts/support-history.md","sha256":"610022f964c2aa00b409fb2723f91b885e306edde5bf73390e880cffd2a5583d"},{"kinds":["contract-source"],"path":"contracts/support-intake.md","sha256":"fd9f732acf67d6c772f4c05d626e4e9e472818fc5226b7ef3d7223b85a0e0bc7"},{"kinds":["contract-source"],"path":"contracts/support-refunds.md","sha256":"da5d0e69bbf3a028dc79f207b940bbd4a79e7f82c68d89f252eb8c73ea16b8bc"},{"kinds":["contract-source"],"path":"contracts/support-triage.md","sha256":"8079080a299674bb0558a6550243051360be1c0f18252708128c3f71af899a0d"},{"kinds":["contract-source"],"path":"contracts/warehouse-administration.md","sha256":"ea037935ce439d10f4ccea3296bb16aa2ddee4e0c13b2b7ade0638ff7cb9b8d6"},{"kinds":["requirement-source"],"path":"prompts/modular/accounts.md","sha256":"0a8dee0847a02da7777c11c4175577c4533fafa538fc09e5124cf4d825e4c96f"},{"kinds":["requirement-source"],"path":"prompts/modular/bundle-checkout.md","sha256":"d3f21ac08991619b5c9aa6ac99a7554340bae991d5b31a25cdb048cdb314936e"},{"kinds":["requirement-source"],"path":"prompts/modular/bundle-returns.md","sha256":"34b3bee882e6a1f6a1527e67d12f8cbdcfd74d026108f9805159123c41015bf2"},{"kinds":["requirement-source"],"path":"prompts/modular/cancellation-conservation.md","sha256":"f383c20f16d75b77dfe2c0ca10dc1c77c998feb80b7c327616512b486c4714f8"},{"kinds":["requirement-source"],"path":"prompts/modular/cancellation-queue.md","sha256":"7e1adf98391a930017acb5c37d46c9b0d17d89e58c939fc57dc52f22e2f86f31"},{"kinds":["requirement-source"],"path":"prompts/modular/cart-expiration.md","sha256":"7c66696f044249d5f7f31487efb85e83f4c06b862fbaa3dd142ef2aef6afc2b7"},{"kinds":["requirement-source"],"path":"prompts/modular/cart.md","sha256":"da024de4032661a46574c8ac8dbe3d1baf45ef6ea7115ba1976d7d5c1044afbe"},{"kinds":["requirement-source"],"path":"prompts/modular/catalog-discovery.md","sha256":"9a0785c55d17e577b84ef257de482bcd8bc8c961e9d0760c38472936a1a0062b"},{"kinds":["requirement-source"],"path":"prompts/modular/catalog-items.md","sha256":"36a72da77f42d856b691c93dc587fee6d9d7f88b722a9893fc226b1d5bb5d3fe"},{"kinds":["requirement-source"],"path":"prompts/modular/catalog-management.md","sha256":"93fece29e1d68513732398c815fe4ebc83079e705e2b9de40df543281439f390"},{"kinds":["requirement-source"],"path":"prompts/modular/checkout-recovery-specification.md","sha256":"0e851fea800d81cb558f8004f04e628e5ccf9f6e5589a9d2f6fceaf33e50f207"},{"kinds":["requirement-source"],"path":"prompts/modular/checkout.md","sha256":"bb834dec7858349a17a8980eb13459a606cdbd2b1c534f468f666459c1a24ba7"},{"kinds":["requirement-source"],"path":"prompts/modular/customer-profile.md","sha256":"f4ffc5d2a642bbccec9eb5c428a37b2d9bfaa1c9f96648d8544bfcf2fe8187bb"},{"kinds":["requirement-source"],"path":"prompts/modular/delivery-notifications.md","sha256":"12d6db9061749779dcb3db699a492781b34ae955c4c11cbb3e5dc2c8e0300ef3"},{"kinds":["requirement-source"],"path":"prompts/modular/faceted-search.md","sha256":"5dc13b47abcbc85654c82148f44b854979d868578db50db42e060c773edc2207"},{"kinds":["requirement-source"],"path":"prompts/modular/inventory-dashboard.md","sha256":"d2190c809ce459141cfdb716d25d38b01f7aca2ce8b8f74128e731e4e3fede07"},{"kinds":["requirement-source"],"path":"prompts/modular/l1-external-sync-specifications.md","sha256":"7f0486045ef1b18271d1b004515f3a1dbf76d09ed62eb7c0683b099100b7f903"},{"kinds":["requirement-source"],"path":"prompts/modular/l1-specifications.md","sha256":"bc3ab63f33d9bbc59fde776c7fdc83ecfdf3d087be78e2596538b7d6945fdd8a"},{"kinds":["requirement-source"],"path":"prompts/modular/l3-specifications.md","sha256":"e6b9877c0f28ec287e510367a810221d09f9b48bb506f7c3cde4eb4450a3eaf4"},{"kinds":["requirement-source"],"path":"prompts/modular/later-specifications.md","sha256":"097745468f48a0589fd9dd81ad98d3ca0ce9455678156fc74d2331e403a77a39"},{"kinds":["requirement-source"],"path":"prompts/modular/managed-support.md","sha256":"33abfe9e7514c6826df60572557d54f2e1570477afeae14c64bb3c5f3bad5fb6"},{"kinds":["requirement-source"],"path":"prompts/modular/notification-preferences.md","sha256":"496baa70ef300e6874f6dbf58ccd2bac594e53101875fd68740e27779d11871b"},{"kinds":["requirement-source"],"path":"prompts/modular/operations-access.md","sha256":"1699a8d0466e115874e49b8ae73bb0004c3c620a03d3aa04dd83818b6c798003"},{"kinds":["requirement-source"],"path":"prompts/modular/order-accounting.md","sha256":"c83044972a6f53a723dcba9ef9dec157eeacb4d2059b790a426da255134364d0"},{"kinds":["requirement-source"],"path":"prompts/modular/order-cancellation.md","sha256":"7d429d4e8db546961e7ec9a12fb5dcba5efd0562c8059ab354121fd5ed13ea84"},{"kinds":["requirement-source"],"path":"prompts/modular/order-delivery.md","sha256":"40483d0bf91c81efe57a61d62dbda756498792383bed9af595cdd8878a0b0cb8"},{"kinds":["requirement-source"],"path":"prompts/modular/order-ownership.md","sha256":"1f4e5149768d1d0a4917ca9b711f1f40bf2c783ee5d59a42ab307f01babb052e"},{"kinds":["requirement-source"],"path":"prompts/modular/order-returns.md","sha256":"7277266f1e8c7d660ee38ba55ac1359200e56c695862c6d7d755d6ec6a6cb808"},{"kinds":["requirement-source"],"path":"prompts/modular/order-support.md","sha256":"f515fe9827373e110633245df158ce8f78ca040f6c25a059d3885182515abb9a"},{"kinds":["requirement-source"],"path":"prompts/modular/payment-records.md","sha256":"ab5c9c913041e324cad82fe6a135d78906818afa3c9a5c204289142c1d696f09"},{"kinds":["requirement-source"],"path":"prompts/modular/price-authorization.md","sha256":"6e9f949bd45f3bc816336de6e7db6dd18254ceebe6ecacc8e0abfd5f3887b8b5"},{"kinds":["requirement-source"],"path":"prompts/modular/price-history-orders.md","sha256":"005e1db32c0c5e4c4f52c1834f82c3d35c7118912c86580b4295a34e9ff12d3e"},{"kinds":["requirement-source"],"path":"prompts/modular/price-history.md","sha256":"9edb3db98af12f3a08cae7887dd6da91c746be49597f086457fc2ecb70c558b8"},{"kinds":["requirement-source"],"path":"prompts/modular/product-bundles.md","sha256":"a0805178ebbb20ea290994de65b4ded503c37798af59905d47c1cb2fd4e2c467"},{"kinds":["requirement-source"],"path":"prompts/modular/production-specifications.md","sha256":"a49cc5aae32bfb035b878e297ee67c1aa8b83ca90e7c73c3dd0cf9f919ae1cf6"},{"kinds":["requirement-source"],"path":"prompts/modular/progression-automatic-reorder.md","sha256":"64751064e699c709a6550daba6fee8f019f445b817910e1ed0d8831632fa2471"},{"kinds":["requirement-source"],"path":"prompts/modular/progression-cart-recovery.md","sha256":"4dc64aaa87d54a05bd7cce31bdc98254e605251d14f1688b859e9aa908da6a8b"},{"kinds":["requirement-source"],"path":"prompts/modular/progression-framing.md","sha256":"33042f5721843cd3796c8545c2a01a32e6d9b341192036321f6532f5ed0e03d2"},{"kinds":["requirement-source"],"path":"prompts/modular/progression-personalized-recommendations.md","sha256":"6c78b3963318b18da11173f96bed5cb8e5537f49e0008342ff11209fada3e099"},{"kinds":["requirement-source"],"path":"prompts/modular/promotion-checkout.md","sha256":"1979ce8991b38fab30c4ea0d0fb7adba51d79bb82981059b0dafded82fed843a"},{"kinds":["requirement-source"],"path":"prompts/modular/promotion-reporting.md","sha256":"3285eb0a50ceeed40b3415bdab8d6f5fc4138e496d2062a08c5ee2fac70157c6"},{"kinds":["requirement-source"],"path":"prompts/modular/promotion-rules.md","sha256":"7a43b632e8fd43b8060100f9614476e41003e47afa04dd1b7c3b09639f6280b2"},{"kinds":["requirement-source"],"path":"prompts/modular/purchasing.md","sha256":"059073391cf92eef2fb1edb710ec1a62747e82115c2bd0251274111b92f93e46"},{"kinds":["requirement-source"],"path":"prompts/modular/recommendation-feedback.md","sha256":"072a548ae797773041e86cbc62f39011559ca7ab40441bee6b77ec1854cd7f51"},{"kinds":["requirement-source"],"path":"prompts/modular/recommendations.md","sha256":"0eed3feb6fc6acf86260d74eeff557b15837aaa09a857c63cf9dee848cd7201f"},{"kinds":["requirement-source"],"path":"prompts/modular/reservations.md","sha256":"e45b53568066c7200486453f78fdbbe89a116259a4d83d9435bde350316595e0"},{"kinds":["requirement-source"],"path":"prompts/modular/review-access.md","sha256":"430fe60b2f028f67eab9f23b572238d4dacc60f7b89d74f8030618368455f371"},{"kinds":["requirement-source"],"path":"prompts/modular/reviews.md","sha256":"1649822528e1bbcfedc59b3c8c5d7ff1b5f0e42e1e82b81ee7e59361cbefab33"},{"kinds":["requirement-source"],"path":"prompts/modular/sales-dashboard.md","sha256":"c65aaadb1f8da6e2b5f7967cc3bcf07beb0e7a860351e866373667bc33012dbd"},{"kinds":["requirement-source"],"path":"prompts/modular/scheduled-restocks.md","sha256":"ba32547038c681f7214219e5a10df75dbf925ee19d4ba60db5b291570f9c16ec"},{"kinds":["requirement-source"],"path":"prompts/modular/search-ordering-specification.md","sha256":"77d88f2b03c71b6cdc8350020ffd7815cf0bee87e4155c1aa00beb9bb81a83f8"},{"kinds":["requirement-source"],"path":"prompts/modular/shipping-authorization.md","sha256":"f336e9c8e1ea425c3dc44e72fabbc5e9e0e2a3541cab3750dd8e112b6c7997f8"},{"kinds":["requirement-source"],"path":"prompts/modular/split-tender-refunds.md","sha256":"c21e00af3623136de4ae45f089b45b457a34563eb37a756d5b8b3563d1f19734"},{"kinds":["requirement-source"],"path":"prompts/modular/staff-access.md","sha256":"10c6aedbc5c60b440d6d0b5c38bb57363ae021c54d62ee2ffe2294d7f6741550"},{"kinds":["requirement-source"],"path":"prompts/modular/staff-activity.md","sha256":"0cb274acefc0d75cd82415de0eb167133db0412e1de4f0fd59f62983d29a1476"},{"kinds":["requirement-source"],"path":"prompts/modular/staff-roles.md","sha256":"951f617a191161df8b9061b304ad568bb5a942070e72142ddf4b93c3dd099951"},{"kinds":["requirement-source"],"path":"prompts/modular/stock-alerts.md","sha256":"3478629a2831e04baca5eec1d3a2a3695c03f6044c36b43acb7c8ca7e35e9867"},{"kinds":["requirement-source"],"path":"prompts/modular/stock-conservation.md","sha256":"4551438e045bb65b44127d3f92dcb79548c78dc1ecc42d2c7807a599d6c59c8f"},{"kinds":["requirement-source"],"path":"prompts/modular/stock-transfers.md","sha256":"6e2f0735d81fd5376b851893404873af4807b83e807e078cca0b8c9a9920e627"},{"kinds":["requirement-source"],"path":"prompts/modular/store-credit.md","sha256":"d769da6c0ef4eb2fa6ac241aeddb61e8e2d85a0f1fcfd595fbf2c6660f67cd7b"},{"kinds":["requirement-source"],"path":"prompts/modular/subscriptions.md","sha256":"ca93ab01c0d23c2fb3c035981372dc1254b219f1875b9566c0d01123176cc7c1"},{"kinds":["requirement-source"],"path":"prompts/modular/support-history.md","sha256":"df2ca2664901a90814eab17d5f7c029595ef614d76ee29eeb4204d9f4f371429"},{"kinds":["requirement-source"],"path":"prompts/modular/support-intake.md","sha256":"048f11b71b66dadf80c77b5d9aef8bbff2b2030171eeda5012dce74ae16421ed"},{"kinds":["requirement-source"],"path":"prompts/modular/support-refunds.md","sha256":"79090320de03a74660418da9e9adbf8170f8c574be990faeaf3d7df652221aa6"},{"kinds":["requirement-source"],"path":"prompts/modular/support-triage.md","sha256":"bbb35abcbae9b8d3782ee3eb94f3175428edfe3fa564d6b0e3af2e0050e10dee"},{"kinds":["requirement-source"],"path":"prompts/modular/transfer-authorization.md","sha256":"6d1e33c7a6aa209ad3f2705607a839dde5c915b65d78a8bb10b9e0da29172c0b"},{"kinds":["requirement-source"],"path":"prompts/modular/warehouse-administration.md","sha256":"8fa2d7b54b3c3d9601ae69bbfee5bdf389f68fea0d0ef4032201af12d3f424a2"},{"kinds":["scenario"],"path":"scenarios/01-account-create.json","sha256":"f37b83a76ff787e12aae1c86fa91b5a2483bfb1aef9497c291e2a374a4376f45"},{"kinds":["scenario"],"path":"scenarios/01-account-duplicate.json","sha256":"f699c90ca3b1af3eda1b73e3c38a4a7cce19b779afa2f9b208c9ead6fdbf15ba"},{"kinds":["scenario"],"path":"scenarios/01-account-password.json","sha256":"35ea9a3a824444096d9d0a51388296c7c35fc833a532b5252f1df9fc5cfab125"},{"kinds":["scenario"],"path":"scenarios/01-account-reload.json","sha256":"574de181769f0d2fa1a88f1131b2a033385fdd576f9aa5088e95781cbd2266d4"},{"kinds":["scenario"],"path":"scenarios/01-account-signout.json","sha256":"7ce90ffda1338d99e37a87ea5beecaeaaa56adecbeb2f46707d1cf0934e596d1"},{"kinds":["scenario"],"path":"scenarios/01-admin-write-staff.json","sha256":"caf94ac7cbffea4438a343c0883322e090cf83aad743a882fb747c287c89f2a2"},{"kinds":["scenario"],"path":"scenarios/01-buying.json","sha256":"48168c76a51b5e1e6d15573a0891cf90889f99aab78b638a24892f70c55ff257"},{"kinds":["scenario"],"path":"scenarios/01-cart-boundary.json","sha256":"76b9c484f70ac94f0dc1787a1a4e61851bf6586e8d1facc9f970791d47a81777"},{"kinds":["scenario"],"path":"scenarios/01-cart.json","sha256":"88cd43f3f48ae86eeec891677a2817f42f8f6554bad299cfae92889d00262d3c"},{"kinds":["scenario"],"path":"scenarios/01-catalog-ranking.json","sha256":"05436b81ee1fefb5e781f7a68060d41690bcdb7b1b9cb0e7543d183b738f1e14"},{"kinds":["scenario"],"path":"scenarios/01-catalog-search.json","sha256":"a633a4afcdbc5e19cc3189ab5e93c358fad44672a4ec2570fa4569c0e9ee0d02"},{"kinds":["scenario"],"path":"scenarios/01-catalog-values.json","sha256":"6216be4761d0db8ac4480ad1fa1a6d4a628d3a4c022278eb7ebf25105db50ea2"},{"kinds":["scenario"],"path":"scenarios/01-core.json","sha256":"1d7f0cf801d41fb01a4f63b2a414c9d723b0749130d1eefff84730567f9a1614"},{"kinds":["scenario"],"path":"scenarios/01-duplicate-checkout.json","sha256":"b6f470b48e0f504d479376ec25895c1d9c293b1ab52cc9d27a1f626519513290"},{"kinds":["scenario"],"path":"scenarios/01-external-live-sync.json","sha256":"3a3dbe302f7e300ac7e82d680d6fb7c6ee277ec9e175d590f68c1c86569ab752"},{"kinds":["scenario"],"path":"scenarios/01-external-reconnect-sync.json","sha256":"5a9e3822bf5c888709d8fc6e255c29e429ba52be3460d688b8ce0a77ef72e79c"},{"kinds":["scenario"],"path":"scenarios/01-external-reload-sync.json","sha256":"80d9eeb9995c30ae4af156c3d93d42475e8b7de0c1e7dca69d4f882536a5cf86"},{"kinds":["scenario"],"path":"scenarios/01-external-server-restart-sync.json","sha256":"c4dab98e2623e35045fa9dd9f4d251392adf316c7ccacc41982fe16b9a8aa574"},{"kinds":["scenario"],"path":"scenarios/01-last-unit.json","sha256":"499778db939f0392d5576e9ea8feba62cd3f9d7ae07130283cbc3babebc81405"},{"kinds":["scenario"],"path":"scenarios/01-order-ownership.json","sha256":"6bef82c8e28f962d06479e452b2019bf107e4b89cfcda5a11e927f9c518c647b"},{"kinds":["scenario"],"path":"scenarios/01-purchase-attribution.json","sha256":"6e1974179f5bb3c475fd84dc051b3e6f37cf4e02cde17928bc1a68275ce798cc"},{"kinds":["scenario"],"path":"scenarios/01-purchase-session.json","sha256":"219f67e5959209f89ee7179a584bcde6e8ac340bd121cbeb0e25895604d1c614"},{"kinds":["scenario"],"path":"scenarios/01-restock-race.json","sha256":"d37c5071bdb221db025cbe43c6377cc7eca99c62ee6e4720737a32eb60decffa"},{"kinds":["scenario"],"path":"scenarios/01-review-eligibility.json","sha256":"ad387c41d1902fab24915cf9cdeed8a2cd0d7aae26ffc379ae784e61d5c3a277"},{"kinds":["scenario"],"path":"scenarios/01-review-rating-live.json","sha256":"f6d4d0c9ea3bbd1213d130ee1d706e326ffbab33e5b9fd6633fa6ff90fea3e3c"},{"kinds":["scenario"],"path":"scenarios/01-review-uniqueness.json","sha256":"49873dc6cf26204dcebd1038b71bfc5213b091d3d13f5f37c5980998a7f3f8f6"},{"kinds":["scenario"],"path":"scenarios/01-review-visibility.json","sha256":"81360bc6b9735251c7672ee26148912aebcc1426b0be2eca9eecd5e607b927b8"},{"kinds":["scenario"],"path":"scenarios/01-server-price.json","sha256":"24481cb30af8c57ebb26b2adb393b8987642e60ddecdbeff2c0381c122825fdc"},{"kinds":["scenario"],"path":"scenarios/01-warehouse-admin-staff.json","sha256":"5434bf92e5b343862dfcb0e6b26593a71db86c0635222ebb3101f60e00fbea5a"},{"kinds":["scenario"],"path":"scenarios/01-warehouse-stock-live-staff.json","sha256":"708a7bd1df90dba203d6c1236d83a3e6deaaecb6e69b4c2faa4208f773966414"},{"kinds":["scenario"],"path":"scenarios/02-cancellation-queue.json","sha256":"d8758cc074fec24a5d8d1d4395e2edb2a7f376d14d91427df6f70b9a5e8e49ce"},{"kinds":["scenario"],"path":"scenarios/02-fulfilment-access.json","sha256":"ccd33eb7a0fbf80f71c86c963f3fe747581808622a33f842e3aa85d940c20012"},{"kinds":["scenario"],"path":"scenarios/02-fulfilment-live.json","sha256":"54455bebda5a1ef78421b81229d63298fcddae0a8315379c173cca0436e0638f"},{"kinds":["scenario"],"path":"scenarios/02-fulfilment-ship.json","sha256":"3996ecb875ae0ca32eb68053650d0d415246487aac909c5de901789f39d64913"},{"kinds":["scenario"],"path":"scenarios/02-invariants.json","sha256":"23b929b83386165a6fff61ee3cbe6845d5da66e5707cdc1ce8f5ead3207018b4"},{"kinds":["scenario"],"path":"scenarios/02-live-price.json","sha256":"7a905177cae6af15f682ebdb909f695bdee85d3124ee91917cb65e8209a73803"},{"kinds":["scenario"],"path":"scenarios/02-low-stock.json","sha256":"a985505feaa58e6f80f08865ea08658da174a01d08a1e70b832b5dd8579e5c88"},{"kinds":["scenario"],"path":"scenarios/02-operational-best-sellers.json","sha256":"f887d0f4dd660fb85a80f10d6e6e1c9fcf6f2bf25e79fbbd7ba86227968e8ace"},{"kinds":["scenario"],"path":"scenarios/02-operational-category-totals.json","sha256":"263411fec43db53777309f2d64fcbdeef1b551a2d981ee8aa8b4caa0ea2faa16"},{"kinds":["scenario"],"path":"scenarios/02-operational-recommendations.json","sha256":"7ea0fa0f317f963c9d2d37adef945be9b8f19eb8618f387bda0a5cd6b92f30b1"},{"kinds":["scenario"],"path":"scenarios/02-order-cancellation-core.json","sha256":"a490889daee2a92eeb18eb35cb4050a47df179d02e031286d70848a4f2595787"},{"kinds":["scenario"],"path":"scenarios/02-order-cancellation-history.json","sha256":"304c8eb8477bc63fda3a1d90f11e3a03fd6391001d8a12ec405c14aeaced4ccb"},{"kinds":["scenario"],"path":"scenarios/02-paid-price-history.json","sha256":"84896fdea36b4f267443000306a6a349fc7221772278d96c751516b0330dff5d"},{"kinds":["scenario"],"path":"scenarios/02-queue-warehouse.json","sha256":"212e8e907b85aff9e4047e7f6f4258d3078aa78ac6bc1df21abb980759322cf2"},{"kinds":["scenario"],"path":"scenarios/02-self-contained.json","sha256":"aad3ce91dae1a94c0f230bab33b0c7a7942337db51f4f9cde06d1d9e2cc99300"},{"kinds":["scenario"],"path":"scenarios/02-server-actions.json","sha256":"a4f22b10cd76a69e6d761818668c7ec52ad064a0a5b1c391a30fde95849b7211"},{"kinds":["scenario"],"path":"scenarios/02-strengthened.json","sha256":"15fc5e537422dbe8dd875cae0b82ac5b5afbf4b65d45ff4545aaea38dd8a9db8"},{"kinds":["scenario"],"path":"scenarios/02-transfer-overdraw.json","sha256":"df6655ff0bb3c9553384ac37f3659af66d6153fef05d31db5e3d3a1d8165f096"},{"kinds":["scenario"],"path":"scenarios/02-transfer-totals.json","sha256":"81462d3b8d4e78f2dd0e207faf285dca472974cd2cab95f723ce735fc3a5c589"},{"kinds":["scenario"],"path":"scenarios/03-cart-expiration.json","sha256":"22a10c3255506dd1bd50ab7caef5187bd0fc3bad3400ad4af9221c811b570d40"},{"kinds":["scenario"],"path":"scenarios/03-deferred-access.json","sha256":"91ed336253f239ed05cb74bf639be7d9ec0f29bb9b372261295ea7d9babc7098"},{"kinds":["scenario"],"path":"scenarios/03-deferred-durability.json","sha256":"fc425c650e26f4be6134cfdbf590423073fd9e2ebac5ee852b646df7a599a954"},{"kinds":["scenario"],"path":"scenarios/03-deferred-integrity.json","sha256":"5bc1faefe4b3d2547b19afc8a5fafb8dbbfef05d45dcb71b2979e0777eb0bcb0"},{"kinds":["scenario"],"path":"scenarios/03-order-delivery.json","sha256":"880e518338a1615825595b983daf64c6e1d68db924ad5fd8c1b205df7e3ff1aa"},{"kinds":["scenario"],"path":"scenarios/03-reservations.json","sha256":"c2460d2b1f1336d1e4c918b6c27ac962d680f8df897a8ca8fd52bdbd403d17ca"},{"kinds":["scenario"],"path":"scenarios/03-scheduled-restock-apply.json","sha256":"74f49d25eea210b9e0209a57261809a585ca28380edfd50084933beff743d2c1"},{"kinds":["scenario"],"path":"scenarios/03-scheduled-restock-cancel.json","sha256":"462df740d24017bc487d961b1547cafdf0e2bc1cea7805dc669d68ff245261bc"},{"kinds":["scenario"],"path":"scenarios/03-scheduled-restocks.json","sha256":"510a8b147738a249b30dce4900e431ca32880de5ea990600aca063c38535b228"},{"kinds":["scenario"],"path":"scenarios/03-server-time.json","sha256":"667e580173187cb4b0f9538336a7e12108e14b5273c9ac663faa5f2325b006be"},{"kinds":["scenario"],"path":"scenarios/progression-account-state-reconnect.json","sha256":"1ead0e72e9375a95cd03caa09bd1fefd858bef7bc910dd6762a53bcee968ce55"},{"kinds":["scenario"],"path":"scenarios/progression-account-state-reload.json","sha256":"fd464513460c640ddcec6ed7e30f9c434a982ae300d16f5233551c14bff45995"},{"kinds":["scenario"],"path":"scenarios/progression-automatic-reorder-access.json","sha256":"ed57cd01a22e7b7a964108ccf1f971f2e8877921015fdd952cb28109cb7be32d"},{"kinds":["scenario"],"path":"scenarios/progression-automatic-reorder-duplicate.json","sha256":"41fe868171047997d33fe6f424bf771fff8d91fc32a19ef749510fa6f41abb57"},{"kinds":["scenario"],"path":"scenarios/progression-automatic-reorder.json","sha256":"91827fedd89c2e268b2b9102d62a89d39dc8d4e07af619d82073c07595c10d57"},{"kinds":["scenario"],"path":"scenarios/progression-books-balance.json","sha256":"6f8d35c97296d36f26ebe07b9b6abc7d73531e4dab495c370a13e80d43adde46"},{"kinds":["scenario"],"path":"scenarios/progression-bundle-checkout.json","sha256":"b26a777560d208a1e415b58dfd46b3662669c4546208d141f0954033ff575a2f"},{"kinds":["scenario"],"path":"scenarios/progression-bundle-returns.json","sha256":"e8d4c983cb11934ac323abbe0ddf55715d75a832133bfd664197677da4911ec8"},{"kinds":["scenario"],"path":"scenarios/progression-cart-checkout.json","sha256":"b49e07cca26e9461db2467cfce31eb43c7b10fb1481a7252353f08d31bf67abd"},{"kinds":["scenario"],"path":"scenarios/progression-cart-recovery.json","sha256":"8c00fd1d2d10091754577acab63319dd593c137ccb75bcbb45cb43bf000b8298"},{"kinds":["scenario"],"path":"scenarios/progression-catalog-management.json","sha256":"a18d83be7f697b89976b062112acd31755b93a702e12b2bd0f6de993f1c9b0e4"},{"kinds":["scenario"],"path":"scenarios/progression-checkout-crash.json","sha256":"024b80278cdcb30ac53a448db82b45ada850d7c22a04ace3aecf296f03b2b1ef"},{"kinds":["scenario"],"path":"scenarios/progression-core-business.json","sha256":"deac867579938f0e41fb16c02e302416d5dcbfd2d20d11a7374236d58c35b8c1"},{"kinds":["scenario"],"path":"scenarios/progression-customer-profile.json","sha256":"7590ab78f8f475fb16fe7959e625da404d29f1e58f9ceb11f51f557648b91829"},{"kinds":["scenario"],"path":"scenarios/progression-delivery-notifications.json","sha256":"62a30dc8ec24d1758e49f90cdaf60856cc465136595347550ae78fe880d2a8a6"},{"kinds":["scenario"],"path":"scenarios/progression-faceted-filters.json","sha256":"b4610dc373d96ad2eeba7c38fb33173ec74250d8ef4941897bb3c48a98cb5368"},{"kinds":["scenario"],"path":"scenarios/progression-faceted-pagination.json","sha256":"c27b5edbd219e2f440ffa29dbad77dbe2da3485437ec9c0071c2d8a99017aeee"},{"kinds":["scenario"],"path":"scenarios/progression-managed-support-privacy.json","sha256":"74da98e1252bb77f0c3b8bf2a9ac788acb7a0104405d786c9a65c51048af7aad"},{"kinds":["scenario"],"path":"scenarios/progression-managed-support-shared.json","sha256":"712852c3d0289ca15efe348797449fcc3b301df5d3d0a9150b188623fced206d"},{"kinds":["scenario"],"path":"scenarios/progression-notification-preferences.json","sha256":"cb494fbc2543347407abe54f74d9cc3cc698f135690f063ebbbff756aec8c807"},{"kinds":["scenario"],"path":"scenarios/progression-open-list-live.json","sha256":"9abcf41a6919dab036d26869c75de0129b12814e9d49bcf80653fa6e61eff1b0"},{"kinds":["scenario"],"path":"scenarios/progression-order-return-boundary.json","sha256":"c404ce6d68113bd69e290bfcfae4b72b14c0a19f63de349dcf79e47563b1f255"},{"kinds":["scenario"],"path":"scenarios/progression-order-return-complete.json","sha256":"02c41f76b4bc60ba0b0e624df540fcd77e7407c90a2e66487672ed6f9c5ed9f2"},{"kinds":["scenario"],"path":"scenarios/progression-order-support-boundary.json","sha256":"9f19a26a9e4d4fe4385f94150bdef6c4e16913f79c5b0fbaede02984ce098362"},{"kinds":["scenario"],"path":"scenarios/progression-order-support-owned.json","sha256":"dda5208d3dbe3a151e683a8cd238f414118553ea0812584f00a82655255cf1a5"},{"kinds":["scenario"],"path":"scenarios/progression-personalized-recommendations.json","sha256":"8bb96bf7c8a81df356cc0e4bd248184dc13924d78bfe85bf173f840899350e1d"},{"kinds":["scenario"],"path":"scenarios/progression-price-cart-checkout.json","sha256":"0e0f6383af25fa70701c7cc99a4b934da2318a68d168ea897333c8be943c8274"},{"kinds":["scenario"],"path":"scenarios/progression-product-bundles.json","sha256":"7d517f3c1265dae451ed4b0ed0f97186b340717561a10f030edd622f5a50163c"},{"kinds":["scenario"],"path":"scenarios/progression-promotion-checkout.json","sha256":"3e6baa221f1ab203893a2a105c809a3f221d985251a64f115d47e2ab58c180ec"},{"kinds":["scenario"],"path":"scenarios/progression-promotion-reporting.json","sha256":"8c9efe46cdeee1d1dd8d802a222bd1f58b06e997dc53a44fd8e19ff45586673e"},{"kinds":["scenario"],"path":"scenarios/progression-promotion-rules.json","sha256":"e49ea26a881a6d49c485a63d7f1f5cca55fb314522d9d948ed5c2f7eb2a84306"},{"kinds":["scenario"],"path":"scenarios/progression-purchasing.json","sha256":"b2aff32949f55c4819bde7b670c00896aacdbfe59f478fa46df9423da455bd12"},{"kinds":["scenario"],"path":"scenarios/progression-recommendation-feedback.json","sha256":"6a6bae970c29cd443a9e6c66919c909a9f0792a8c37a7d00d2c63f5e4be872c3"},{"kinds":["scenario"],"path":"scenarios/progression-review-access.json","sha256":"c416df2ced8caa0cc58002e333ba72c6e1d3dc83a24681240dfe2a2215e8530b"},{"kinds":["scenario"],"path":"scenarios/progression-review-script.json","sha256":"267a9134ddb8cd25d3e9d76b5595e97debd2a8071f8ff8e568aa7285b608d30f"},{"kinds":["scenario"],"path":"scenarios/progression-search-ordering.json","sha256":"b96f50c9ec28d68aa1fe4e6d6ea7631f6399f439025c6fe74c1d9a3ce8a55803"},{"kinds":["scenario"],"path":"scenarios/progression-shipping-accounting.json","sha256":"2e310fb4489c154617660b3d247136646c04faa903e958cf2561e9072615b779"},{"kinds":["scenario"],"path":"scenarios/progression-signed-out-purchase.json","sha256":"59de2a84876ae4542d783dca533764eb4f06bc390a67a37b25f0967477ee44fe"},{"kinds":["scenario"],"path":"scenarios/progression-split-tender-refunds.json","sha256":"39771047c0b0a84a6de5c4178e387c95581667cba5741e24d7a3555bc6a19018"},{"kinds":["scenario"],"path":"scenarios/progression-staff-access.json","sha256":"67de6a963d3cdb33dfb119ffacfdd1024d7f9c4d095bf90d553ef1c6efe235c9"},{"kinds":["scenario"],"path":"scenarios/progression-staff-activity.json","sha256":"28600137357ce5620f9f4919b25eb1ff27ba5aff4ed02285349e4d82cd1585a4"},{"kinds":["scenario"],"path":"scenarios/progression-staff-roles.json","sha256":"d87a2f7f0890a84614f538d7656de92082ba1c5843a40d3b2cf0f7f2d9097e11"},{"kinds":["scenario"],"path":"scenarios/progression-stock-alert-delivery.json","sha256":"e4899fb49e87edd9787997e9abb173c890604397fe096186ea0f601fd2e2f67f"},{"kinds":["scenario"],"path":"scenarios/progression-stock-alerts.json","sha256":"582bcb0bea4f109da56e761ad27c809cfb2da38edec41a9e4a528ea603c020f1"},{"kinds":["scenario"],"path":"scenarios/progression-stock-limit.json","sha256":"e07cd6c2b949b392cbb10f0f7cf8b2e8b74a0ef2ed17d563187ad28387eebc4a"},{"kinds":["scenario"],"path":"scenarios/progression-store-credit.json","sha256":"04a1fc19d215155c90a5382e91e15cbf01b400d6b2f8600b5a0e25b42132c820"},{"kinds":["scenario"],"path":"scenarios/progression-subscriptions.json","sha256":"de31264cfc1890ab6c3ebaead98c41964da70d135d34a5f4944ac41108998e94"},{"kinds":["scenario"],"path":"scenarios/progression-support-history.json","sha256":"86928df21aa68fec5c20993ec13e3b1c57291f38a35167996a99ef34f363a2b7"},{"kinds":["scenario"],"path":"scenarios/progression-support-intake.json","sha256":"c8d01303a3316f28de956fb2a72ab289905a46f5d689fe40b8193e12cea1753a"},{"kinds":["scenario"],"path":"scenarios/progression-support-refunds-access.json","sha256":"52f03c8a7ab8b1c7554f7d637bd5d46a19e24f4be5666eac14398ed1f1b2707b"},{"kinds":["scenario"],"path":"scenarios/progression-support-refunds-accounting.json","sha256":"38be5988391c96acfa7eac25248df674e0fe95e2b58f22ea47fa909a02f01576"},{"kinds":["scenario"],"path":"scenarios/progression-support-refunds-resolution.json","sha256":"2627a122fd791ed4ed2c4c08e7fea283e017bfe59dd1a682899207cc89d7ee67"},{"kinds":["scenario"],"path":"scenarios/progression-support-return-interaction.json","sha256":"7c50a90555a616e9e8ce7fefb771e79237ed2890b28545a5951da2fa52902820"},{"kinds":["scenario"],"path":"scenarios/progression-support-triage.json","sha256":"a0ad2546ae46257154a75fa3250353cd443f1c6dc93ff52b4e666e99444101f5"},{"kinds":["track-manifest"],"path":"track.json","sha256":"ae917ab791cfc59a6ece01cc23ab433a235cc5fb20ab37974d8ed36c494a67d9"}],"sourceManifestSha256":"aab07ac3bb812f5c50efbda67ac9e1605a8e97a6a39b6baa219d762ffc65722f","task":{"baseRecipe":null,"composedSha256":"d063ef87268f9c5a4bb2e7c0f4570cd2ac6b50e9f45e1ca1c1df76049731f650","contractSha256":"e432e08fc81f67f95f38c44e05fc2adc393f10cd29d67af78d0f1676e73b7578","contracts":[{"from":null,"id":"ecommerce.application-interface","modes":["fresh","upgrade"],"order":0,"owners":["recipe"],"path":"contracts/application-interface.md","sha256":"b770db6c1dbf92c106c7501a17028876a30a63655c8f88b5667b44557f401692","until":null},{"from":null,"id":"ecommerce.progression.staff-access-hooks","modes":["fresh","upgrade"],"order":1900,"owners":["ecommerce.progression.staff-access"],"path":"contracts/staff-access.md","sha256":"dcd7b740d5f65160ddf0b4221d29f84426ee89f04560e953add0856cf0bca87a","until":null},{"from":null,"id":"ecommerce.progression.customer-profile-hooks","modes":["upgrade"],"order":1950,"owners":["ecommerce.progression.customer-profile"],"path":"contracts/customer-profile.md","sha256":"7451bf14ada950c9b7ad269d63467154c388e9ea18b97f479037cdd397ca519f","until":null},{"from":null,"id":"ecommerce.progression.staff-role-hooks","modes":["upgrade"],"order":1960,"owners":["ecommerce.progression.staff-roles"],"path":"contracts/staff-roles.md","sha256":"cce6145182485fafcd2adc29cec90af20523a2afd9c952800eefb5d15a49f96e","until":null},{"from":null,"id":"ecommerce.progression.catalog-management-hooks","modes":["upgrade"],"order":1970,"owners":["ecommerce.progression.catalog-management"],"path":"contracts/catalog-management.md","sha256":"5123971185ded331deaef2e323fad31e6133d55fc839289e2c4a0dfc5292ee4e","until":null},{"from":null,"id":"ecommerce.progression.payment-record-hooks","modes":["upgrade"],"order":1980,"owners":["ecommerce.progression.payment-records"],"path":"contracts/payment-records.md","sha256":"8c752352c7f47a0a65d1823f9ec74009dc95088fc6c2a6cc30d1a1dc7fa11fe0","until":null},{"from":null,"id":"ecommerce.progression.staff-activity-hooks","modes":["upgrade"],"order":1990,"owners":["ecommerce.progression.staff-activity"],"path":"contracts/staff-activity.md","sha256":"7e7c1846445f82aa78ad8e32606e6830f9d326ebfea75d13b077c073695c9594","until":null},{"from":null,"id":"ecommerce.feature.catalog-items.hooks","modes":["fresh","upgrade"],"order":2000,"owners":["ecommerce.feature.catalog-items"],"path":"contracts/catalog-items.md","sha256":"596ec08b1f4a6b290595570f3bcf2847a1f60feeb20d90f98d25761666bfe9f2","until":null},{"from":null,"id":"ecommerce.feature.catalog-discovery.hooks","modes":["fresh","upgrade"],"order":2010,"owners":["ecommerce.feature.catalog-discovery"],"path":"contracts/catalog-discovery.md","sha256":"d13ea495f78e3827b7a243b97466aefbf0252980c76edb432b6b0506854e8450","until":null},{"from":null,"id":"ecommerce.l2.transfer-hooks","modes":["upgrade"],"order":2031,"owners":["ecommerce.l2.stock-transfers-features"],"path":"contracts/stock-transfers.md","sha256":"01f28ebb3487559d4689919f0991e43f74fcc85609fa4c810e92adde30e84096","until":null},{"from":null,"id":"ecommerce.l2.price-hooks","modes":["upgrade"],"order":2041,"owners":["ecommerce.l2.price-history-features"],"path":"contracts/price-history.md","sha256":"3465714f91e0e978607900b19377a134e9beb704848e2462b1438465cc2e98ee","until":null},{"from":"# Price history completed-order interface","id":"ecommerce.progression.price-history-order-hooks","modes":["upgrade"],"order":2042,"owners":["ecommerce.progression.price-history-specifications"],"path":"contracts/price-history-orders.md","requiresFeatures":["ecommerce.feature.purchasing","ecommerce.l2.price-history-features"],"sha256":"45d360052ede67e50e12b5c0e64904dbbdd1dd17a430c38130a2b8a70d274278","until":"# Price history cart and checkout interface"},{"from":"# Price history cart and checkout interface","id":"ecommerce.progression.price-history-cart-hooks","modes":["upgrade"],"order":2043,"owners":["ecommerce.progression.price-history-specifications"],"path":"contracts/price-history-orders.md","requiresFeatures":["ecommerce.feature.checkout","ecommerce.l2.price-history-features"],"sha256":"0d80d8f3bb9ced280a6203d2e8974b1a4db923b2d423205969ca1d44d002fc8b","until":null},{"from":null,"id":"ecommerce.l2.inventory-dashboard-hooks","modes":["upgrade"],"order":2050,"owners":["ecommerce.l2.inventory-dashboard"],"path":"contracts/inventory-dashboard.md","sha256":"8c3de4ff8a958776ca087febbbbf5f950eaef9efacb96b7c4fa49357b2d0a371","until":null},{"from":null,"id":"ecommerce.l2.order-cancellation-hooks","modes":["upgrade"],"order":2060,"owners":["ecommerce.l2.order-cancellation-features"],"path":"contracts/order-cancellation.md","sha256":"fc274b1409c50de8edcf797ab83cf8e8c46a54db30ada859f854e1cd40c7dee1","until":null},{"from":null,"id":"ecommerce.l2.sales-dashboard-hooks","modes":["upgrade"],"order":2060,"owners":["ecommerce.l2.sales-dashboard"],"path":"contracts/sales-dashboard.md","sha256":"ff9ed3890aa5c8303a0badecf946e7d98da3fbbb0a2890a693099bab1a2056c0","until":null},{"from":null,"id":"ecommerce.l2.recommendations-hooks","modes":["upgrade"],"order":2070,"owners":["ecommerce.l2.recommendations"],"path":"contracts/recommendations.md","sha256":"ab5417cbf78f43464e82a543e50e9601580bb2b3a57826a9e73da9899f39de16","until":null},{"from":null,"id":"ecommerce.feature.accounts.hooks","modes":["fresh","upgrade"],"order":2100,"owners":["ecommerce.feature.accounts"],"path":"contracts/accounts.md","sha256":"e281aa0cff56c23117203b13d11f6787a7f8163cb8d1b7bc0d2d86b5390cfff6","until":null},{"from":null,"id":"ecommerce.feature.purchasing.hooks","modes":["fresh","upgrade"],"order":2200,"owners":["ecommerce.feature.purchasing"],"path":"contracts/purchasing.md","sha256":"c2d59da67b400d055ab90bf53f2e46a3af9605a1fc68534c2b64d8db2ed3409c","until":null},{"from":null,"id":"ecommerce.feature.cart.hooks","modes":["fresh","upgrade"],"order":2300,"owners":["ecommerce.feature.cart"],"path":"contracts/cart.md","sha256":"bb1b8741b9eb47b5766a330bb1fc23005f7540fdc79d20efdaefb183cf50918d","until":null},{"from":null,"id":"ecommerce.feature.checkout.hooks","modes":["fresh","upgrade"],"order":2310,"owners":["ecommerce.feature.checkout"],"path":"contracts/checkout.md","sha256":"49416683e06d996a28980ff650a3281f89cae062269b7de761899e71759c731c","until":null},{"from":null,"id":"ecommerce.orders.data","modes":["fresh","upgrade"],"order":2315,"owners":["ecommerce.feature.checkout","ecommerce.feature.purchasing"],"path":"contracts/order-data.md","sha256":"7b7cfc6b102f4836235c7f23344865f60156b3e4ac96c3e5cbb0e298390b3b06","until":null},{"from":null,"id":"ecommerce.feature.reviews.hooks","modes":["fresh","upgrade"],"order":2400,"owners":["ecommerce.feature.reviews"],"path":"contracts/reviews.md","sha256":"6be3567258c0c4bf3331e609f63be26ad0bb43ceca3e7da4accaaad8c9ac6541","until":null},{"from":null,"id":"ecommerce.feature.warehouse-admin.hooks","modes":["fresh","upgrade"],"order":2500,"owners":["ecommerce.feature.warehouse-admin"],"path":"contracts/warehouse-administration.md","sha256":"ea037935ce439d10f4ccea3296bb16aa2ddee4e0c13b2b7ade0638ff7cb9b8d6","until":null},{"from":null,"id":"ecommerce.progression.support-history-hooks","modes":["upgrade"],"order":2900,"owners":["ecommerce.progression.support-history"],"path":"contracts/support-history.md","sha256":"610022f964c2aa00b409fb2723f91b885e306edde5bf73390e880cffd2a5583d","until":null},{"from":null,"id":"ecommerce.progression.support-intake-hooks","modes":["fresh","upgrade"],"order":2900,"owners":["ecommerce.progression.support-intake"],"path":"contracts/support-intake.md","sha256":"fd9f732acf67d6c772f4c05d626e4e9e472818fc5226b7ef3d7223b85a0e0bc7","until":null},{"from":null,"id":"ecommerce.progression.support-triage-hooks","modes":["upgrade"],"order":2900,"owners":["ecommerce.progression.support-triage"],"path":"contracts/support-triage.md","sha256":"8079080a299674bb0558a6550243051360be1c0f18252708128c3f71af899a0d","until":null},{"from":null,"id":"ecommerce.progression.fulfilment-queue-hooks","modes":["upgrade"],"order":2920,"owners":["ecommerce.progression.fulfilment-queue"],"path":"contracts/operations-access.md","sha256":"fd9c31482b484dc1f9bf3c521d247971334e1f52f51a7548a987bdebc65dbdb5","until":null},{"from":null,"id":"ecommerce.progression.promotion-rules-hooks","modes":["upgrade"],"order":2950,"owners":["ecommerce.progression.promotion-rules"],"path":"contracts/promotion-rules.md","sha256":"f352f8bb938aa874125b10bbb6182643f04b6d1ce82cde41512bd16835a7b90b","until":null},{"from":null,"id":"ecommerce.progression.notification-preferences-hooks","modes":["upgrade"],"order":2990,"owners":["ecommerce.progression.notification-preferences"],"path":"contracts/notification-preferences.md","sha256":"d6b4231f67d5e70a03ec331545b6419acf766b52841c8520b94963c16aa13fec","until":null},{"from":null,"id":"ecommerce.l3.reservation-hooks","modes":["upgrade"],"order":3900,"owners":["ecommerce.l3.reservations-features"],"path":"contracts/reservations.md","sha256":"e1c4af7a67dd200d5f18d550e5b4c30e7a4bbaf60600b434108ebff7bdf90627","until":null},{"from":null,"id":"ecommerce.progression.managed-support-hooks","modes":["upgrade"],"order":3900,"owners":["ecommerce.progression.managed-support"],"path":"contracts/managed-support.md","sha256":"458b89a7f786086a95957c778943660068cd6c00b30635fd1cd786c37df76398","until":null},{"from":null,"id":"ecommerce.l3.scheduled-restock-hooks","modes":["upgrade"],"order":3910,"owners":["ecommerce.l3.scheduled-restocks-features"],"path":"contracts/scheduled-restocks.md","sha256":"a946c0954a641d4fe64b933761e2b92d546ae08ee434d676c6faed3ed8b03c8e","until":null},{"from":null,"id":"ecommerce.l3.order-delivery-hooks","modes":["upgrade"],"order":3920,"owners":["ecommerce.l3.order-delivery-features"],"path":"contracts/order-delivery.md","sha256":"74bd21b39c8d5f020ff62cc408992c15788e48eba8e05a76a0cddc4b4920a98e","until":null},{"from":null,"id":"ecommerce.l3.cart-expiration-hooks","modes":["upgrade"],"order":3930,"owners":["ecommerce.l3.cart-expiration-features"],"path":"contracts/cart-expiration.md","sha256":"56c0966494cd19b629140f8b8d53e8b9838e34668a5cab6b7cccb41b78734c50","until":null},{"from":null,"id":"ecommerce.progression.promotion-checkout-hooks","modes":["upgrade"],"order":3950,"owners":["ecommerce.progression.promotion-checkout"],"path":"contracts/promotion-checkout.md","sha256":"b74e703dc77c9eeec26f5beb41cab102570c8314d817015c858557e9946293aa","until":null},{"from":null,"id":"ecommerce.progression.stock-alert-hooks","modes":["upgrade"],"order":3990,"owners":["ecommerce.progression.stock-alerts"],"path":"contracts/stock-alerts.md","sha256":"405f106569c84b3062f8159452730f16adadf12d804c554a570e39b958b63421","until":null},{"from":null,"id":"ecommerce.l3.order-return-hooks","modes":["upgrade"],"order":4041,"owners":["ecommerce.l3.order-returns-features"],"path":"contracts/order-returns.md","sha256":"fe0668ab3bf00d4c167794dbecb75b26b23cb62dfc0a1b79636a013edb237329","until":null},{"from":null,"id":"ecommerce.progression.faceted-search-hooks","modes":["upgrade"],"order":4900,"owners":["ecommerce.progression.faceted-search"],"path":"contracts/faceted-search.md","sha256":"08ace4d2d1947f16ceb4da95e6993086c9bd77a0977c258fef1f0a96c7e7879d","until":null},{"from":null,"id":"ecommerce.progression.order-support-hooks","modes":["upgrade"],"order":4900,"owners":["ecommerce.progression.order-support"],"path":"contracts/order-support.md","sha256":"a2901e66af870055b6c3c26f240132ae08f3cb93d0c52a7b2573c9dc153e1e03","until":null},{"from":null,"id":"ecommerce.progression.personalized-recommendation-hooks","modes":["upgrade"],"order":4910,"owners":["ecommerce.progression.personalized-recommendations"],"path":"contracts/progression-personalized-recommendations.md","sha256":"42389a6d284dcfdb53a610ce5ce77d40dbc2b9d5e177bbd3f6bccc40079c7d98","until":null},{"from":null,"id":"ecommerce.progression.promotion-reporting-hooks","modes":["upgrade"],"order":4950,"owners":["ecommerce.progression.promotion-reporting"],"path":"contracts/promotion-reporting.md","sha256":"81cded5fd9a8822c8756ea50bedb879971c94f8727d176f22fa53d2a6a1efbb0","until":null},{"from":null,"id":"ecommerce.feature.store-credit.interface","modes":["upgrade"],"order":5900,"owners":["ecommerce.feature.store-credit"],"path":"contracts/store-credit.md","sha256":"505ca48dfc4f9f2d6ea38e53e1bd382910264d0195be8580b5fb01f7e7074713","until":null},{"from":null,"id":"ecommerce.feature.subscriptions.interface","modes":["upgrade"],"order":5900,"owners":["ecommerce.feature.subscriptions"],"path":"contracts/subscriptions.md","sha256":"dc533bc7f3b9be03ae7d9e18c2e02ffa996bf934b9ba230826d492b4cefa045e","until":null},{"from":null,"id":"ecommerce.progression.delivery-notification-hooks","modes":["upgrade"],"order":5900,"owners":["ecommerce.progression.delivery-notifications"],"path":"contracts/delivery-notifications.md","sha256":"4bf565ea751bb5278bae5910420beeb531a2eb88fb5755e5a06dda68860af490","until":null},{"from":null,"id":"ecommerce.progression.support-refund-hooks","modes":["upgrade"],"order":5900,"owners":["ecommerce.progression.support-refunds"],"path":"contracts/support-refunds.md","sha256":"da5d0e69bbf3a028dc79f207b940bbd4a79e7f82c68d89f252eb8c73ea16b8bc","until":null},{"from":null,"id":"ecommerce.progression.automatic-reorder-hooks","modes":["upgrade"],"order":5910,"owners":["ecommerce.progression.automatic-reorder"],"path":"contracts/progression-automatic-reorder.md","sha256":"3e70361965e6ddeb7b05cc7ad5348e363d58d628734de96b8a9792e68e71cc72","until":null},{"from":null,"id":"ecommerce.progression.cart-recovery-hooks","modes":["upgrade"],"order":5920,"owners":["ecommerce.progression.cart-recovery"],"path":"contracts/progression-cart-recovery.md","sha256":"daf04aea3082483caa2ebf3a3c89a438329600cb6aa5d74fb47d97bc244e5747","until":null},{"from":null,"id":"ecommerce.progression.recommendation-feedback-hooks","modes":["upgrade"],"order":5930,"owners":["ecommerce.progression.recommendation-feedback"],"path":"contracts/recommendation-feedback.md","sha256":"00a96f594c8da1ffb4a933c6f8d8d0219216ab6cc2c781cfd17dd9c97c517d58","until":null},{"from":null,"id":"ecommerce.feature.split-tender-refunds.interface","modes":["upgrade"],"order":6900,"owners":["ecommerce.feature.split-tender-refunds"],"path":"contracts/split-tender-refunds.md","sha256":"62b8b3c233d33858e9b696d06d94c70f6524f8cbed77028acc0d2affdd780841","until":null},{"from":null,"id":"ecommerce.interface.product-bundles","modes":["upgrade"],"order":8104,"owners":["ecommerce.feature.product-bundles"],"path":"contracts/product-bundles.md","sha256":"b27905002b693e6c63532cd8193c8e3fd1fdeaad85041d84b8240a2092bf1c57","until":null},{"from":null,"id":"ecommerce.interface.bundle-checkout","modes":["upgrade"],"order":8105,"owners":["ecommerce.feature.bundle-checkout"],"path":"contracts/bundle-checkout.md","sha256":"2c4e70b620934dc927ad4c84c17e54b6e9cef665ba3b098f9f2fc9e79a3c4c3e","until":null},{"from":null,"id":"ecommerce.interface.bundle-returns","modes":["upgrade"],"order":8106,"owners":["ecommerce.feature.bundle-returns"],"path":"contracts/bundle-returns.md","sha256":"69f8bf6afc325a98bab38235e49eaa2875bc674e6a61c7559692593018c9f527","until":null}],"mode":"action","requirementSha256":"bd057cbfbcae06db5bdd6a7eb20d03ae00f9c16cff9841199b342a7df5b19279","requirements":[{"from":null,"id":"ecommerce.progression.fresh","modes":["fresh"],"order":0,"owners":["recipe"],"path":"prompts/modular/progression-framing.md","sha256":"7c3267ef4ef6a454ba26217d8a0efc47f1cbe655970fbb1ddfd2ae7637e17df1","until":"## Existing application"},{"from":"## Existing application","id":"ecommerce.progression.upgrade","modes":["upgrade"],"order":0,"owners":["recipe"],"path":"prompts/modular/progression-framing.md","sha256":"ad2dc327dea4410a715b013d9455c37060a193b844c7de7967ce760ef1c2c118","until":null},{"from":null,"id":"ecommerce.l2.inventory-dashboard","modes":["upgrade"],"order":50,"owners":["ecommerce.l2.inventory-dashboard"],"path":"prompts/modular/inventory-dashboard.md","sha256":"d2190c809ce459141cfdb716d25d38b01f7aca2ce8b8f74128e731e4e3fede07","until":null},{"from":null,"id":"ecommerce.l2.sales-dashboard","modes":["upgrade"],"order":60,"owners":["ecommerce.l2.sales-dashboard"],"path":"prompts/modular/sales-dashboard.md","sha256":"c65aaadb1f8da6e2b5f7967cc3bcf07beb0e7a860351e866373667bc33012dbd","until":null},{"from":null,"id":"ecommerce.l2.recommendations","modes":["upgrade"],"order":70,"owners":["ecommerce.l2.recommendations"],"path":"prompts/modular/recommendations.md","sha256":"0eed3feb6fc6acf86260d74eeff557b15837aaa09a857c63cf9dee848cd7201f","until":null},{"from":null,"id":"ecommerce.feature.accounts.requirement","modes":["fresh","upgrade"],"order":100,"owners":["ecommerce.feature.accounts"],"path":"prompts/modular/accounts.md","sha256":"0a8dee0847a02da7777c11c4175577c4533fafa538fc09e5124cf4d825e4c96f","until":null},{"from":null,"id":"ecommerce.feature.catalog-items.requirement","modes":["fresh","upgrade"],"order":200,"owners":["ecommerce.feature.catalog-items"],"path":"prompts/modular/catalog-items.md","sha256":"36a72da77f42d856b691c93dc587fee6d9d7f88b722a9893fc226b1d5bb5d3fe","until":null},{"from":null,"id":"ecommerce.feature.catalog-discovery.requirement","modes":["fresh","upgrade"],"order":210,"owners":["ecommerce.feature.catalog-discovery"],"path":"prompts/modular/catalog-discovery.md","sha256":"9a0785c55d17e577b84ef257de482bcd8bc8c961e9d0760c38472936a1a0062b","until":null},{"from":null,"id":"ecommerce.feature.purchasing.requirement","modes":["fresh","upgrade"],"order":300,"owners":["ecommerce.feature.purchasing"],"path":"prompts/modular/purchasing.md","sha256":"059073391cf92eef2fb1edb710ec1a62747e82115c2bd0251274111b92f93e46","until":null},{"from":null,"id":"ecommerce.feature.cart.requirement","modes":["fresh","upgrade"],"order":400,"owners":["ecommerce.feature.cart"],"path":"prompts/modular/cart.md","sha256":"da024de4032661a46574c8ac8dbe3d1baf45ef6ea7115ba1976d7d5c1044afbe","until":null},{"from":null,"id":"ecommerce.feature.checkout.requirement","modes":["fresh","upgrade"],"order":410,"owners":["ecommerce.feature.checkout"],"path":"prompts/modular/checkout.md","sha256":"bb834dec7858349a17a8980eb13459a606cdbd2b1c534f468f666459c1a24ba7","until":null},{"from":null,"id":"ecommerce.feature.reviews.requirement","modes":["fresh","upgrade"],"order":500,"owners":["ecommerce.feature.reviews"],"path":"prompts/modular/reviews.md","sha256":"1649822528e1bbcfedc59b3c8c5d7ff1b5f0e42e1e82b81ee7e59361cbefab33","until":null},{"from":null,"id":"ecommerce.feature.warehouse-admin.requirement","modes":["fresh","upgrade"],"order":600,"owners":["ecommerce.feature.warehouse-admin"],"path":"prompts/modular/warehouse-administration.md","sha256":"8fa2d7b54b3c3d9601ae69bbfee5bdf389f68fea0d0ef4032201af12d3f424a2","until":null},{"from":"## Access control: purchasing","id":"ecommerce.spec.access-control.purchasing","modes":["fresh"],"order":1000,"owners":["ecommerce.spec.access-control"],"path":"prompts/modular/l1-specifications.md","requiresFeatures":["ecommerce.feature.purchasing"],"sha256":"45c2ac9e423af1431c6a9d8b7de707b7d6a8402c004c5472c56d7efe387e61a1","until":"## Access control: warehouse administration"},{"from":"## Access control: warehouse administration","id":"ecommerce.spec.access-control.warehouse-admin","modes":["fresh"],"order":1010,"owners":["ecommerce.spec.access-control"],"path":"prompts/modular/l1-specifications.md","requiresFeatures":["ecommerce.feature.warehouse-admin"],"sha256":"02500e3bded8076287f0b4c7264fe48ff3c766b0ab9aa386497c5cc66fc725f4","until":"## Access control: reviews"},{"from":"## Access control: reviews","id":"ecommerce.spec.access-control.reviews","modes":["fresh"],"order":1020,"owners":["ecommerce.spec.access-control"],"path":"prompts/modular/l1-specifications.md","requiresFeatures":["ecommerce.feature.reviews"],"sha256":"10d4140e8f649ddf46843100231683f13143c09226195cfe487827b662333f4d","until":"## Access control: cart"},{"from":"## Access control: cart","id":"ecommerce.spec.access-control.cart","modes":["fresh"],"order":1030,"owners":["ecommerce.spec.access-control"],"path":"prompts/modular/l1-specifications.md","requiresFeatures":["ecommerce.feature.cart"],"sha256":"353e3d5daa87c988456b392ad53fd93bdf473b5a860049104cd5acdaddf05cee","until":"## State durability: accounts"},{"from":null,"id":"ecommerce.progression.staff-access","modes":["fresh","upgrade"],"order":1100,"owners":["ecommerce.progression.staff-access"],"path":"prompts/modular/staff-access.md","sha256":"10c6aedbc5c60b440d6d0b5c38bb57363ae021c54d62ee2ffe2294d7f6741550","until":null},{"from":"## State durability: accounts","id":"ecommerce.spec.state-durability.accounts","modes":["fresh"],"order":1100,"owners":["ecommerce.spec.state-durability"],"path":"prompts/modular/l1-specifications.md","requiresFeatures":["ecommerce.feature.accounts"],"sha256":"3466c8854dd16c38beafe194fb402f8f5c5539defb90a9b856c357347255c3ee","until":"## State durability: account data"},{"from":"## State durability: account data","id":"ecommerce.spec.state-durability.account-data","modes":["fresh"],"order":1110,"owners":["ecommerce.spec.state-durability"],"path":"prompts/modular/l1-specifications.md","requiresFeatures":["ecommerce.feature.accounts","ecommerce.feature.cart"],"sha256":"db7e1e0fbf6e6f2956f28ef00dfc7191c90ca05349a605f246776ff3c6f4e2d9","until":"## Live state: catalog and purchasing"},{"from":null,"id":"ecommerce.spec.state-durability.checkout-crash","modes":["fresh","upgrade"],"order":1120,"owners":["ecommerce.spec.state-durability"],"path":"prompts/modular/checkout-recovery-specification.md","requiresFeatures":["ecommerce.feature.checkout"],"sha256":"0e851fea800d81cb558f8004f04e628e5ccf9f6e5589a9d2f6fceaf33e50f207","until":null},{"from":null,"id":"ecommerce.progression.customer-profile","modes":["upgrade"],"order":1200,"owners":["ecommerce.progression.customer-profile"],"path":"prompts/modular/customer-profile.md","sha256":"f4ffc5d2a642bbccec9eb5c428a37b2d9bfaa1c9f96648d8544bfcf2fe8187bb","until":null},{"from":null,"id":"ecommerce.progression.support-intake","modes":["fresh","upgrade"],"order":1200,"owners":["ecommerce.progression.support-intake"],"path":"prompts/modular/support-intake.md","sha256":"048f11b71b66dadf80c77b5d9aef8bbff2b2030171eeda5012dce74ae16421ed","until":null},{"from":"## Live state: catalog and purchasing","id":"ecommerce.spec.live-state.catalog-purchasing","modes":["fresh"],"order":1200,"owners":["ecommerce.spec.live-state"],"path":"prompts/modular/l1-specifications.md","requiresFeatures":["ecommerce.feature.catalog-items","ecommerce.feature.purchasing"],"sha256":"3bfd8cf26509ffeeb475df0eee040f4743cc31acd9e8292e4144b46055686b55","until":"## Live state: cart"},{"from":"## Live state: cart","id":"ecommerce.spec.live-state.cart","modes":["fresh"],"order":1210,"owners":["ecommerce.spec.live-state"],"path":"prompts/modular/l1-specifications.md","requiresFeatures":["ecommerce.feature.cart"],"sha256":"244ee5cf7387c74dd1776e659964e782f042229eff84918de2517781ad095045","until":"## Live state: reviews"},{"from":"## Live state: reviews","id":"ecommerce.spec.live-state.reviews","modes":["fresh"],"order":1220,"owners":["ecommerce.spec.live-state"],"path":"prompts/modular/l1-specifications.md","requiresFeatures":["ecommerce.feature.reviews"],"sha256":"aeeab5a0dda0f1df6b1ab3ae78d3c1c6a9ff2f108ac1d09e904c27b7ee71100d","until":"## Live state: warehouse administration"},{"from":"## Live state: warehouse administration","id":"ecommerce.spec.live-state.warehouse-admin","modes":["fresh"],"order":1230,"owners":["ecommerce.spec.live-state"],"path":"prompts/modular/l1-specifications.md","requiresFeatures":["ecommerce.feature.catalog-items","ecommerce.feature.warehouse-admin"],"sha256":"362d4ef3422a09d060cdd5b09837b0a4a1f67b8fb108f59dcf7afb4a12d2a4e5","until":"## Concurrency safety: purchasing"},{"from":null,"id":"ecommerce.progression.staff-roles","modes":["upgrade"],"order":1250,"owners":["ecommerce.progression.staff-roles"],"path":"prompts/modular/staff-roles.md","sha256":"175a323c92238509111aa9c366e4ec302d508edc872077ecd26d8acbcbe21ba9","until":null},{"from":null,"id":"ecommerce.progression.catalog-management","modes":["upgrade"],"order":1300,"owners":["ecommerce.progression.catalog-management"],"path":"prompts/modular/catalog-management.md","sha256":"93fece29e1d68513732398c815fe4ebc83079e705e2b9de40df543281439f390","until":null},{"from":"## Concurrency safety: purchasing","id":"ecommerce.spec.concurrency-safety.purchasing","modes":["fresh"],"order":1300,"owners":["ecommerce.spec.concurrency-safety"],"path":"prompts/modular/l1-specifications.md","requiresFeatures":["ecommerce.feature.purchasing"],"sha256":"e2995c00f9971e1389bc03b56faf4e03da9c83a84cb205ddfeb84964bd4a905f","until":"## Concurrency safety: restocking"},{"from":"## Concurrency safety: restocking","id":"ecommerce.spec.concurrency-safety.restocking","modes":["fresh"],"order":1310,"owners":["ecommerce.spec.concurrency-safety"],"path":"prompts/modular/l1-specifications.md","requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.warehouse-admin"],"sha256":"958e12514579d21f92a73806ba6983912f1828f40f51efeb16947e7a6c3d539e","until":"## Concurrency safety: checkout"},{"from":"## Concurrency safety: checkout","id":"ecommerce.spec.concurrency-safety.checkout","modes":["fresh"],"order":1320,"owners":["ecommerce.spec.concurrency-safety"],"path":"prompts/modular/l1-specifications.md","requiresFeatures":["ecommerce.feature.checkout"],"sha256":"0bb644068b430d491cfd6c6f5af00cf16cff7ec930a1d8b3150493e4d0bebbe5","until":"## Transactional integrity: reviews"},{"from":null,"id":"ecommerce.progression.payment-records","modes":["upgrade"],"order":1350,"owners":["ecommerce.progression.payment-records"],"path":"prompts/modular/payment-records.md","sha256":"ab5c9c913041e324cad82fe6a135d78906818afa3c9a5c204289142c1d696f09","until":null},{"from":null,"id":"ecommerce.progression.staff-activity","modes":["upgrade"],"order":1400,"owners":["ecommerce.progression.staff-activity"],"path":"prompts/modular/staff-activity.md","sha256":"0cb274acefc0d75cd82415de0eb167133db0412e1de4f0fd59f62983d29a1476","until":null},{"from":"## Transactional integrity: reviews","id":"ecommerce.spec.transactional-integrity.reviews","modes":["fresh"],"order":1400,"owners":["ecommerce.spec.transactional-integrity"],"path":"prompts/modular/l1-specifications.md","requiresFeatures":["ecommerce.feature.reviews"],"sha256":"715afabddf7a8ed221f38fdba2b89dad7d0b656c62f5e607153ef39ec52e2fc0","until":"## Transactional integrity: purchasing"},{"from":"## Transactional integrity: purchasing","id":"ecommerce.spec.transactional-integrity.purchasing","modes":["fresh"],"order":1410,"owners":["ecommerce.spec.transactional-integrity"],"path":"prompts/modular/l1-specifications.md","requiresFeatures":["ecommerce.feature.purchasing"],"sha256":"1452a3c92e5a35b5bed9273e146de8d1dda3011105ec5d79821462629ef56c8d","until":"## Transactional integrity: warehouse accounting"},{"from":"## Transactional integrity: warehouse accounting","id":"ecommerce.spec.transactional-integrity.warehouse-accounting","modes":["fresh"],"order":1420,"owners":["ecommerce.spec.transactional-integrity"],"path":"prompts/modular/l1-specifications.md","requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.warehouse-admin"],"sha256":"667b2197f1e9c20e22f03abc7cc756b98b421377adfdb3fd06f35005837c3948","until":"## External data synchronization"},{"from":"## External data synchronization","id":"ecommerce.spec.external-data-sync.requirement","modes":["fresh","upgrade"],"order":1500,"owners":["ecommerce.spec.external-data-sync"],"path":"prompts/modular/l1-external-sync-specifications.md","requiresFeatures":["ecommerce.feature.warehouse-admin"],"sha256":"0e3db28232aedb57b3fb2fbb9afa3ca65fcad28b8c050e1965feee4db32e4239","until":null},{"from":null,"id":"ecommerce.progression.fulfilment-queue","modes":["upgrade"],"order":2020,"owners":["ecommerce.progression.fulfilment-queue"],"path":"prompts/modular/operations-access.md","sha256":"1699a8d0466e115874e49b8ae73bb0004c3c620a03d3aa04dd83818b6c798003","until":null},{"from":null,"id":"ecommerce.l2.stock-transfer","modes":["upgrade"],"order":2030,"owners":["ecommerce.l2.stock-transfers-features"],"path":"prompts/modular/stock-transfers.md","sha256":"6e2f0735d81fd5376b851893404873af4807b83e807e078cca0b8c9a9920e627","until":null},{"from":null,"id":"ecommerce.l2.order-cancellation","modes":["upgrade"],"order":2040,"owners":["ecommerce.l2.order-cancellation-features"],"path":"prompts/modular/order-cancellation.md","sha256":"7d429d4e8db546961e7ec9a12fb5dcba5efd0562c8059ab354121fd5ed13ea84","until":null},{"from":null,"id":"ecommerce.l2.price-history","modes":["upgrade"],"order":2040,"owners":["ecommerce.l2.price-history-features"],"path":"prompts/modular/price-history.md","sha256":"9edb3db98af12f3a08cae7887dd6da91c746be49597f086457fc2ecb70c558b8","until":null},{"from":"## Price history: completed orders","id":"ecommerce.progression.price-history-orders","modes":["upgrade"],"order":2041,"owners":["ecommerce.progression.price-history-specifications"],"path":"prompts/modular/price-history-orders.md","requiresFeatures":["ecommerce.feature.purchasing","ecommerce.l2.price-history-features"],"sha256":"12abf44d08a49b076c721b62c4fc240a82c0fb350b10a3eb052afcf2ee78c6b6","until":"## Price history: cart and checkout"},{"from":"## Price history: cart and checkout","id":"ecommerce.progression.price-history-cart-checkout","modes":["upgrade"],"order":2042,"owners":["ecommerce.progression.price-history-specifications"],"path":"prompts/modular/price-history-orders.md","requiresFeatures":["ecommerce.feature.checkout","ecommerce.l2.price-history-features"],"sha256":"86caeac95b2d3cb1fc0ec0d467ee52303218d087ca30c24eb38c7c7714c8ec2b","until":null},{"from":null,"id":"ecommerce.progression.cancellation-queue","modes":["upgrade"],"order":2045,"owners":["ecommerce.progression.cancellation-queue-specifications"],"path":"prompts/modular/cancellation-queue.md","requiresFeatures":["ecommerce.l2.order-cancellation-features","ecommerce.progression.fulfilment-queue"],"sha256":"7e1adf98391a930017acb5c37d46c9b0d17d89e58c939fc57dc52f22e2f86f31","until":null},{"from":"## Cancellation accounting","id":"ecommerce.progression.cancellation-accounting","modes":["upgrade"],"order":2100,"owners":["ecommerce.progression.cancellation-accounting-specifications"],"path":"prompts/modular/order-accounting.md","requiresFeatures":["ecommerce.l2.order-cancellation-features"],"sha256":"a31e83bef57e79d545be549b9905d1b1f178e40a34e676ec18a62dfddf916d8d","until":"## Price accounting"},{"from":null,"id":"ecommerce.progression.support-triage","modes":["upgrade"],"order":2100,"owners":["ecommerce.progression.support-triage"],"path":"prompts/modular/support-triage.md","sha256":"bbb35abcbae9b8d3782ee3eb94f3175428edfe3fa564d6b0e3af2e0050e10dee","until":null},{"from":"## Price accounting","id":"ecommerce.progression.price-accounting","modes":["upgrade"],"order":2110,"owners":["ecommerce.progression.price-accounting-specifications"],"path":"prompts/modular/order-accounting.md","requiresFeatures":["ecommerce.l2.price-history-features"],"sha256":"64f96277738b0a33453e69bdcb1d79971d979a57ec27b8caacc96b499bc43de5","until":null},{"from":null,"id":"ecommerce.progression.support-history","modes":["upgrade"],"order":2110,"owners":["ecommerce.progression.support-history"],"path":"prompts/modular/support-history.md","sha256":"df2ca2664901a90814eab17d5f7c029595ef614d76ee29eeb4204d9f4f371429","until":null},{"from":null,"id":"ecommerce.progression.promotion-rules","modes":["upgrade"],"order":2200,"owners":["ecommerce.progression.promotion-rules"],"path":"prompts/modular/promotion-rules.md","sha256":"7a43b632e8fd43b8060100f9614476e41003e47afa04dd1b7c3b09639f6280b2","until":null},{"from":null,"id":"ecommerce.progression.notification-preferences","modes":["upgrade"],"order":2300,"owners":["ecommerce.progression.notification-preferences"],"path":"prompts/modular/notification-preferences.md","sha256":"496baa70ef300e6874f6dbf58ccd2bac594e53101875fd68740e27779d11871b","until":null},{"from":null,"id":"ecommerce.progression.transfer-authorization","modes":["upgrade"],"order":2930,"owners":["ecommerce.progression.operations-access-specifications"],"path":"prompts/modular/transfer-authorization.md","requiresFeatures":["ecommerce.l2.stock-transfers-features"],"sha256":"6d1e33c7a6aa209ad3f2705607a839dde5c915b65d78a8bb10b9e0da29172c0b","until":null},{"from":null,"id":"ecommerce.progression.price-authorization","modes":["upgrade"],"order":2940,"owners":["ecommerce.progression.operations-access-specifications"],"path":"prompts/modular/price-authorization.md","requiresFeatures":["ecommerce.l2.price-history-features"],"sha256":"6e9f949bd45f3bc816336de6e7db6dd18254ceebe6ecacc8e0abfd5f3887b8b5","until":null},{"from":null,"id":"ecommerce.progression.shipping-authorization","modes":["upgrade"],"order":2950,"owners":["ecommerce.progression.operations-access-specifications"],"path":"prompts/modular/shipping-authorization.md","requiresFeatures":["ecommerce.progression.fulfilment-queue"],"sha256":"f336e9c8e1ea425c3dc44e72fabbc5e9e0e2a3541cab3750dd8e112b6c7997f8","until":null},{"from":null,"id":"ecommerce.progression.order-ownership","modes":["upgrade"],"order":2960,"owners":["ecommerce.progression.operations-access-specifications"],"path":"prompts/modular/order-ownership.md","requiresFeatures":["ecommerce.l2.order-cancellation-features"],"sha256":"1f4e5149768d1d0a4917ca9b711f1f40bf2c783ee5d59a42ab307f01babb052e","until":null},{"from":null,"id":"ecommerce.progression.review-access","modes":["upgrade"],"order":2970,"owners":["ecommerce.progression.review-access-specifications"],"path":"prompts/modular/review-access.md","requiresFeatures":["ecommerce.feature.reviews"],"sha256":"430fe60b2f028f67eab9f23b572238d4dacc60f7b89d74f8030618368455f371","until":null},{"from":null,"id":"ecommerce.progression.transfer-conservation","modes":["upgrade"],"order":2970,"owners":["ecommerce.progression.inventory-conservation-specifications"],"path":"prompts/modular/stock-conservation.md","requiresFeatures":["ecommerce.l2.stock-transfers-features"],"sha256":"4551438e045bb65b44127d3f92dcb79548c78dc1ecc42d2c7807a599d6c59c8f","until":null},{"from":null,"id":"ecommerce.progression.cancellation-conservation","modes":["upgrade"],"order":2980,"owners":["ecommerce.progression.inventory-conservation-specifications"],"path":"prompts/modular/cancellation-conservation.md","requiresFeatures":["ecommerce.l2.order-cancellation-features"],"sha256":"f383c20f16d75b77dfe2c0ca10dc1c77c998feb80b7c327616512b486c4714f8","until":null},{"from":null,"id":"ecommerce.l3.reservations","modes":["upgrade"],"order":3000,"owners":["ecommerce.l3.reservations-features"],"path":"prompts/modular/reservations.md","sha256":"e45b53568066c7200486453f78fdbbe89a116259a4d83d9435bde350316595e0","until":null},{"from":null,"id":"ecommerce.l3.scheduled-restocks","modes":["upgrade"],"order":3010,"owners":["ecommerce.l3.scheduled-restocks-features"],"path":"prompts/modular/scheduled-restocks.md","sha256":"ba32547038c681f7214219e5a10df75dbf925ee19d4ba60db5b291570f9c16ec","until":null},{"from":null,"id":"ecommerce.l3.order-delivery","modes":["upgrade"],"order":3020,"owners":["ecommerce.l3.order-delivery-features"],"path":"prompts/modular/order-delivery.md","sha256":"40483d0bf91c81efe57a61d62dbda756498792383bed9af595cdd8878a0b0cb8","until":null},{"from":null,"id":"ecommerce.l3.cart-expiration","modes":["upgrade"],"order":3030,"owners":["ecommerce.l3.cart-expiration-features"],"path":"prompts/modular/cart-expiration.md","sha256":"7c66696f044249d5f7f31487efb85e83f4c06b862fbaa3dd142ef2aef6afc2b7","until":null},{"from":"## Durable reservations","id":"ecommerce.l3.durable-reservations","modes":["upgrade"],"order":3100,"owners":["ecommerce.l3.deferred-durability-specifications"],"path":"prompts/modular/l3-specifications.md","requiresFeatures":["ecommerce.l3.reservations-features"],"sha256":"18ec31e622e6d392c68eacef275c6595125aa9bc45296e6064be50353b228bc6","until":"## Durable restocks"},{"from":null,"id":"ecommerce.progression.managed-support","modes":["upgrade"],"order":3100,"owners":["ecommerce.progression.managed-support"],"path":"prompts/modular/managed-support.md","sha256":"33abfe9e7514c6826df60572557d54f2e1570477afeae14c64bb3c5f3bad5fb6","until":null},{"from":"## Durable restocks","id":"ecommerce.l3.durable-restocks","modes":["upgrade"],"order":3101,"owners":["ecommerce.l3.deferred-durability-specifications"],"path":"prompts/modular/l3-specifications.md","requiresFeatures":["ecommerce.l3.scheduled-restocks-features"],"sha256":"40c3fac2bde0e10b85416906bcd0080e9748c916820ca44918074f2d342f7deb","until":"## Durable order delivery"},{"from":"## Durable order delivery","id":"ecommerce.l3.durable-order-delivery","modes":["upgrade"],"order":3102,"owners":["ecommerce.l3.deferred-durability-specifications"],"path":"prompts/modular/l3-specifications.md","requiresFeatures":["ecommerce.l3.order-delivery-features"],"sha256":"56a0e9d3113f8c49d563d6a99940e8ee272c32adb841c1dbb5533b17705a1e69","until":"## Durable cart expiration"},{"from":"## Durable cart expiration","id":"ecommerce.l3.durable-cart-expiration","modes":["upgrade"],"order":3103,"owners":["ecommerce.l3.deferred-durability-specifications"],"path":"prompts/modular/l3-specifications.md","requiresFeatures":["ecommerce.l3.cart-expiration-features"],"sha256":"1c81d51182e1a7648dc8e1e34cf1e80aade556a1eaeb63f79ba49b50bf2c2997","until":"## Exactly-once restocks"},{"from":"## Exactly-once restocks","id":"ecommerce.l3.exactly-once-restocks","modes":["upgrade"],"order":3110,"owners":["ecommerce.l3.deferred-integrity-specifications"],"path":"prompts/modular/l3-specifications.md","requiresFeatures":["ecommerce.l3.scheduled-restocks-features"],"sha256":"2fe8adca82a8fd5bb0fa1ba02cbb88e9f4ae3c799c49cf0980451d85603b6515","until":"## Exactly-once delivery"},{"from":"## Exactly-once delivery","id":"ecommerce.l3.exactly-once-delivery","modes":["upgrade"],"order":3111,"owners":["ecommerce.l3.deferred-integrity-specifications"],"path":"prompts/modular/l3-specifications.md","requiresFeatures":["ecommerce.l3.order-delivery-features"],"sha256":"70fa7a5b7e6a074950652a574684c4230545cd3b3b21645e568edf45dea5d44f","until":"## Server-timed restocks"},{"from":"## Server-timed restocks","id":"ecommerce.l3.server-timed-restocks","modes":["upgrade"],"order":3120,"owners":["ecommerce.l3.server-time-specifications"],"path":"prompts/modular/l3-specifications.md","requiresFeatures":["ecommerce.l3.scheduled-restocks-features"],"sha256":"ffb402340b8e0afa1973da971a48ed9534bf615e36c213dc892f7dc7260a9da3","until":"## Server-timed reservations"},{"from":"## Server-timed reservations","id":"ecommerce.l3.server-timed-reservations","modes":["upgrade"],"order":3121,"owners":["ecommerce.l3.server-time-specifications"],"path":"prompts/modular/l3-specifications.md","requiresFeatures":["ecommerce.l3.reservations-features"],"sha256":"108cb53bdda3f4a651347cec50a2236bb5cbbb01b9f92943fd6d287f151789bc","until":"## Deferred-work access"},{"from":"## Deferred-work access","id":"ecommerce.l3.deferred-access","modes":["upgrade"],"order":3130,"owners":["ecommerce.l3.deferred-access-specifications"],"path":"prompts/modular/l3-specifications.md","requiresFeatures":["ecommerce.l3.scheduled-restocks-features"],"sha256":"72874aad78d6da1f467443015f53f82514e45866b09a17c6435b16ec72b4e26f","until":"## Stock conservation"},{"from":"## Stock conservation","id":"ecommerce.l3.stock-conservation","modes":["upgrade"],"order":3140,"owners":["ecommerce.l3.deferred-integrity-specifications"],"path":"prompts/modular/l3-specifications.md","requiresFeatures":["ecommerce.l3.reservations-features"],"sha256":"cf7ef3381b7b3d4beee90d314b4a00d667a89909b67d6fd57f453329a6c48be3","until":null},{"from":null,"id":"ecommerce.progression.promotion-checkout","modes":["upgrade"],"order":3200,"owners":["ecommerce.progression.promotion-checkout"],"path":"prompts/modular/promotion-checkout.md","sha256":"1979ce8991b38fab30c4ea0d0fb7adba51d79bb82981059b0dafded82fed843a","until":null},{"from":null,"id":"ecommerce.progression.stock-alerts","modes":["upgrade"],"order":3300,"owners":["ecommerce.progression.stock-alerts"],"path":"prompts/modular/stock-alerts.md","sha256":"3478629a2831e04baca5eec1d3a2a3695c03f6044c36b43acb7c8ca7e35e9867","until":null},{"from":null,"id":"ecommerce.progression.faceted-search","modes":["upgrade"],"order":4000,"owners":["ecommerce.progression.faceted-search"],"path":"prompts/modular/faceted-search.md","sha256":"5dc13b47abcbc85654c82148f44b854979d868578db50db42e060c773edc2207","until":null},{"from":null,"id":"ecommerce.progression.personalized-recommendations","modes":["upgrade"],"order":4010,"owners":["ecommerce.progression.personalized-recommendations"],"path":"prompts/modular/progression-personalized-recommendations.md","sha256":"6c78b3963318b18da11173f96bed5cb8e5537f49e0008342ff11209fada3e099","until":null},{"from":null,"id":"ecommerce.spec.search-ordering","modes":["fresh","upgrade"],"order":4010,"owners":["ecommerce.spec.search-ordering"],"path":"prompts/modular/search-ordering-specification.md","requiresFeatures":["ecommerce.feature.purchasing","ecommerce.progression.faceted-search"],"sha256":"77d88f2b03c71b6cdc8350020ffd7815cf0bee87e4155c1aa00beb9bb81a83f8","until":null},{"from":null,"id":"ecommerce.l3.order-returns","modes":["upgrade"],"order":4040,"owners":["ecommerce.l3.order-returns-features"],"path":"prompts/modular/order-returns.md","sha256":"7277266f1e8c7d660ee38ba55ac1359200e56c695862c6d7d755d6ec6a6cb808","until":null},{"from":null,"id":"ecommerce.progression.order-support","modes":["upgrade"],"order":4100,"owners":["ecommerce.progression.order-support"],"path":"prompts/modular/order-support.md","sha256":"f515fe9827373e110633245df158ce8f78ca040f6c25a059d3885182515abb9a","until":null},{"from":null,"id":"ecommerce.progression.promotion-reporting","modes":["upgrade"],"order":4200,"owners":["ecommerce.progression.promotion-reporting"],"path":"prompts/modular/promotion-reporting.md","sha256":"3285eb0a50ceeed40b3415bdab8d6f5fc4138e496d2062a08c5ee2fac70157c6","until":null},{"from":null,"id":"ecommerce.progression.delivery-notifications","modes":["upgrade"],"order":5000,"owners":["ecommerce.progression.delivery-notifications"],"path":"prompts/modular/delivery-notifications.md","sha256":"12d6db9061749779dcb3db699a492781b34ae955c4c11cbb3e5dc2c8e0300ef3","until":null},{"from":null,"id":"ecommerce.progression.automatic-reorder","modes":["upgrade"],"order":5010,"owners":["ecommerce.progression.automatic-reorder"],"path":"prompts/modular/progression-automatic-reorder.md","sha256":"64751064e699c709a6550daba6fee8f019f445b817910e1ed0d8831632fa2471","until":null},{"from":null,"id":"ecommerce.progression.cart-recovery","modes":["upgrade"],"order":5020,"owners":["ecommerce.progression.cart-recovery"],"path":"prompts/modular/progression-cart-recovery.md","sha256":"4dc64aaa87d54a05bd7cce31bdc98254e605251d14f1688b859e9aa908da6a8b","until":null},{"from":null,"id":"ecommerce.progression.recommendation-feedback","modes":["upgrade"],"order":5030,"owners":["ecommerce.progression.recommendation-feedback"],"path":"prompts/modular/recommendation-feedback.md","sha256":"072a548ae797773041e86cbc62f39011559ca7ab40441bee6b77ec1854cd7f51","until":null},{"from":null,"id":"ecommerce.feature.store-credit","modes":["upgrade"],"order":5100,"owners":["ecommerce.feature.store-credit"],"path":"prompts/modular/store-credit.md","sha256":"d769da6c0ef4eb2fa6ac241aeddb61e8e2d85a0f1fcfd595fbf2c6660f67cd7b","until":null},{"from":null,"id":"ecommerce.feature.subscriptions","modes":["upgrade"],"order":5100,"owners":["ecommerce.feature.subscriptions"],"path":"prompts/modular/subscriptions.md","sha256":"ca93ab01c0d23c2fb3c035981372dc1254b219f1875b9566c0d01123176cc7c1","until":null},{"from":null,"id":"ecommerce.progression.support-refunds","modes":["upgrade"],"order":5100,"owners":["ecommerce.progression.support-refunds"],"path":"prompts/modular/support-refunds.md","sha256":"79090320de03a74660418da9e9adbf8170f8c574be990faeaf3d7df652221aa6","until":null},{"from":"## automatic-reorder-access","id":"ecommerce.spec.access-control.automatic-reorder-access","modes":["upgrade"],"order":6001,"owners":["ecommerce.spec.access-control"],"path":"prompts/modular/production-specifications.md","requiresFeatures":["ecommerce.progression.automatic-reorder"],"sha256":"f93257ed878a9fc27e9a0b80ceb050ab44e5ced5f6ba3d868939e8dee9ed49b1","until":"## recommendation-profile-isolation"},{"from":"## recommendation-profile-isolation","id":"ecommerce.spec.access-control.recommendation-profile-isolation","modes":["upgrade"],"order":6002,"owners":["ecommerce.spec.access-control"],"path":"prompts/modular/production-specifications.md","requiresFeatures":["ecommerce.progression.personalized-recommendations"],"sha256":"36fe3efec8aa2529e48f5f2ef809256a97957554e2a349e669fddcc3d6942a5a","until":"## staff-activity-privacy"},{"from":"## staff-activity-privacy","id":"ecommerce.spec.access-control.staff-activity-privacy","modes":["upgrade"],"order":6003,"owners":["ecommerce.spec.access-control"],"path":"prompts/modular/production-specifications.md","requiresFeatures":["ecommerce.progression.staff-activity"],"sha256":"3d9a91bd3c10abf3594a2dc690077f5a3b1ed95ddb7257c7c49f8e666448949c","until":"## order-support-ownership"},{"from":"## order-support-ownership","id":"ecommerce.spec.access-control.order-support-ownership","modes":["upgrade"],"order":6004,"owners":["ecommerce.spec.access-control"],"path":"prompts/modular/production-specifications.md","requiresFeatures":["ecommerce.progression.order-support"],"sha256":"5e090901a9bbfe7b0f1869be90a16d8d9df30b735effc5cd55e63784443aad05","until":"## delivery-notification-privacy"},{"from":"## delivery-notification-privacy","id":"ecommerce.spec.access-control.delivery-notification-privacy","modes":["upgrade"],"order":6005,"owners":["ecommerce.spec.access-control"],"path":"prompts/modular/production-specifications.md","requiresFeatures":["ecommerce.feature.purchasing","ecommerce.progression.delivery-notifications","ecommerce.progression.fulfilment-queue"],"sha256":"4fbdbdc513c7cc363198ce55780a421261c057f54ac8a44e3a69908d792d2e22","until":"## support-refund-access"},{"from":"## support-refund-access","id":"ecommerce.spec.access-control.support-refund-access","modes":["upgrade"],"order":6006,"owners":["ecommerce.spec.access-control"],"path":"prompts/modular/production-specifications.md","requiresFeatures":["ecommerce.progression.support-refunds"],"sha256":"a4200b390cf7c85d467425834af2642ceb7a80fa9ee53cccdfaa565d6ff69684","until":"## recommendation-feedback-privacy"},{"from":"## recommendation-feedback-privacy","id":"ecommerce.spec.access-control.recommendation-feedback-privacy","modes":["upgrade"],"order":6007,"owners":["ecommerce.spec.access-control"],"path":"prompts/modular/production-specifications.md","requiresFeatures":["ecommerce.progression.recommendation-feedback"],"sha256":"3df273f53ccd54520a89fedb64952b990ff4f61c36d16a50bd1f28e8523471b2","until":"## recommendation-feedback-restart"},{"from":"## recommendation-feedback-restart","id":"ecommerce.spec.state-durability.recommendation-feedback-restart","modes":["upgrade"],"order":6008,"owners":["ecommerce.spec.state-durability"],"path":"prompts/modular/production-specifications.md","requiresFeatures":["ecommerce.progression.recommendation-feedback"],"sha256":"5531638e5123f8c7c76c6f095ba3dadb52128482acc6d325de997ec280656d7c","until":"## automatic-reorder-deduplication"},{"from":"## automatic-reorder-deduplication","id":"ecommerce.spec.transactional-integrity.automatic-reorder-deduplication","modes":["upgrade"],"order":6009,"owners":["ecommerce.spec.transactional-integrity"],"path":"prompts/modular/production-specifications.md","requiresFeatures":["ecommerce.feature.purchasing","ecommerce.progression.automatic-reorder"],"sha256":"de82b9029ce5ae8c90dc1ea20a024da19d8ea55eac6ab36f6fa1d84b8b241b01","until":"## payment-deduplication"},{"from":"## payment-deduplication","id":"ecommerce.spec.transactional-integrity.payment-deduplication","modes":["upgrade"],"order":6010,"owners":["ecommerce.spec.transactional-integrity"],"path":"prompts/modular/production-specifications.md","requiresFeatures":["ecommerce.progression.payment-records"],"sha256":"f33fb61f31726bbe7e8b617ae12d970a8d876d98d30d49191dd0043a58557760","until":"## support-refund-accounting"},{"from":"## support-refund-accounting","id":"ecommerce.spec.transactional-integrity.support-refund-accounting","modes":["upgrade"],"order":6011,"owners":["ecommerce.spec.transactional-integrity"],"path":"prompts/modular/production-specifications.md","requiresFeatures":["ecommerce.progression.support-refunds"],"sha256":"bd44a5a8c9211493896869df9b086177b022d9840f9a362d0c609e3c6bff6877","until":null},{"from":null,"id":"ecommerce.feature.split-tender-refunds","modes":["upgrade"],"order":6100,"owners":["ecommerce.feature.split-tender-refunds"],"path":"prompts/modular/split-tender-refunds.md","sha256":"c21e00af3623136de4ae45f089b45b457a34563eb37a756d5b8b3563d1f19734","until":null},{"from":"## Product bundles","id":"ecommerce.spec.bundle-integrity.product-bundles","modes":["fresh","upgrade"],"order":6500,"owners":["ecommerce.spec.bundle-integrity"],"path":"prompts/modular/later-specifications.md","requiresFeatures":["ecommerce.feature.product-bundles"],"sha256":"7eb9ee1c794134867f6b27ad3b773bbd99d4c860774618d1286d39b4347470fb","until":"## Bundle checkout"},{"from":"## Bundle checkout","id":"ecommerce.spec.bundle-integrity.bundle-checkout","modes":["fresh","upgrade"],"order":6501,"owners":["ecommerce.spec.bundle-integrity"],"path":"prompts/modular/later-specifications.md","requiresFeatures":["ecommerce.feature.bundle-checkout"],"sha256":"630eead6de0dc2d9672e83e64beb8cb5036eccd9ba4aaf7c9284d91c0e42144b","until":"## Bundle returns"},{"from":"## Bundle returns","id":"ecommerce.spec.bundle-integrity.bundle-returns","modes":["fresh","upgrade"],"order":6502,"owners":["ecommerce.spec.bundle-integrity"],"path":"prompts/modular/later-specifications.md","requiresFeatures":["ecommerce.feature.bundle-returns"],"sha256":"7a2264753c8088c30ecc87cb1f98940198fde663b5a4a1bb8de83c410e01e5b2","until":"## Store credit"},{"from":"## Store credit","id":"ecommerce.spec.store-credit.store-credit","modes":["fresh","upgrade"],"order":6503,"owners":["ecommerce.spec.store-credit"],"path":"prompts/modular/later-specifications.md","requiresFeatures":["ecommerce.feature.store-credit"],"sha256":"ee64f04e0f30fc269021083c4b02c26f9fc87321d41d7a7262e68bf6926b7c83","until":"## Split-tender refunds"},{"from":"## Split-tender refunds","id":"ecommerce.spec.split-tender-refunds.split-tender-refunds","modes":["fresh","upgrade"],"order":6504,"owners":["ecommerce.spec.split-tender-refunds"],"path":"prompts/modular/later-specifications.md","requiresFeatures":["ecommerce.feature.split-tender-refunds"],"sha256":"860929486a2d9e283be8486c85b1ee2086936b22de28db17febf5a1e65bc10ff","until":"## Scheduled purchases"},{"from":"## Scheduled purchases","id":"ecommerce.spec.subscriptions.subscriptions","modes":["fresh","upgrade"],"order":6505,"owners":["ecommerce.spec.subscriptions"],"path":"prompts/modular/later-specifications.md","requiresFeatures":["ecommerce.feature.subscriptions"],"sha256":"69f32aaf688858b89cb8fc56352b1674e13fd18b7b9454da3ba9a025e24c90ab","until":null},{"from":null,"id":"ecommerce.feature.product-bundles","modes":["upgrade"],"order":8004,"owners":["ecommerce.feature.product-bundles"],"path":"prompts/modular/product-bundles.md","sha256":"a0805178ebbb20ea290994de65b4ded503c37798af59905d47c1cb2fd4e2c467","until":null},{"from":null,"id":"ecommerce.feature.bundle-checkout","modes":["upgrade"],"order":8005,"owners":["ecommerce.feature.bundle-checkout"],"path":"prompts/modular/bundle-checkout.md","sha256":"d3f21ac08991619b5c9aa6ac99a7554340bae991d5b31a25cdb048cdb314936e","until":null},{"from":null,"id":"ecommerce.feature.bundle-returns","modes":["upgrade"],"order":8006,"owners":["ecommerce.feature.bundle-returns"],"path":"prompts/modular/bundle-returns.md","sha256":"34b3bee882e6a1f6a1527e67d12f8cbdcfd74d026108f9805159123c41015bf2","until":null}]},"title":"Ecommerce progression catalog","track":"ecommerce"},"meaning":{"checks":[{"category":"feature","checkGroupId":"accounts","criterionId":"1a","description":"a visitor can create an account and is signed in as it","featureId":1,"featureName":"Accounts","note":null,"packId":"ecommerce.feature.accounts","points":1,"provenBy":null,"role":"feature","semantics":[{"do":"signUp","name":"ann"},{"contains":"ann","do":"expect"}],"source":"scenarios/01-account-create.json","stableKey":"ecommerce.feature.accounts.accounts.1a","statedBy":"a visitor can create an account with a username and password","withheld":null},{"category":"production","checkGroupId":"accounts","criterionId":"1b","description":"a taken username is refused and does not sign the visitor in as the existing account","featureId":1,"featureName":"Accounts","note":null,"packId":"ecommerce.feature.accounts","points":1,"provenBy":null,"role":"feature","semantics":[{"do":"signUp","expectFailure":true,"name":"ann","password":"different-pw"},{"do":"expect"},{"absent":true,"do":"expect"}],"source":"scenarios/01-account-duplicate.json","stableKey":"ecommerce.feature.accounts.accounts.1b","statedBy":"signing up with a taken username fails with a visible error and must never sign the visitor in as the existing account","withheld":null},{"category":"production","checkGroupId":"accounts","criterionId":"1c","description":"a wrong password is refused","featureId":1,"featureName":"Accounts","note":null,"packId":"ecommerce.feature.accounts","points":1,"provenBy":null,"role":"feature","semantics":[{"do":"signIn","expectFailure":true,"name":"ann","password":"wrong-pw"},{"do":"expect"},{"absent":true,"do":"expect"}],"source":"scenarios/01-account-password.json","stableKey":"ecommerce.feature.accounts.accounts.1c","statedBy":"signing in with a wrong password fails with a visible error","withheld":null},{"category":"production","checkGroupId":"session-reload","criterionId":"1e","description":"the session survives a reload","featureId":1,"featureName":"Accounts","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.state-durability","points":1,"provenBy":null,"requiresFeatures":["ecommerce.feature.accounts"],"role":"guarantee","semantics":[{"do":"reload"},{"contains":"ann","do":"expect"}],"source":"scenarios/01-account-reload.json","stableKey":"ecommerce.spec.state-durability.session-reload.1e","statedBy":"a signed-in session persists across a page reload","withheld":null},{"category":"feature","checkGroupId":"accounts","criterionId":"1d","description":"signing out and back in returns the same account","featureId":1,"featureName":"Accounts","note":null,"packId":"ecommerce.feature.accounts","points":1,"provenBy":null,"role":"feature","semantics":[{"do":"click","unlessVisible":"signout"},{"do":"click"},{"do":"waitUntilAbsent"},{"do":"signIn","name":"ann"},{"contains":"ann","do":"expect"}],"source":"scenarios/01-account-signout.json","stableKey":"ecommerce.feature.accounts.accounts.1d","statedBy":"a signed-in user can sign out, returning to the signed-out state","withheld":null},{"category":"feature","checkGroupId":"admin-write","criterionId":"103a","description":"an administrator can restock a warehouse","featureId":103,"featureName":"Only an administrator can restock","note":null,"packId":"ecommerce.feature.warehouse-admin","points":1,"provenBy":null,"role":"feature","semantics":[{"as":"purifier-before-control","do":"recordNumber"},{"action":"restock","do":"callAction","input":{"attribute":"data-restock-input","contains":"Air Purifier","testid":"admin-location-row"},"namedAction":{"args":[0,0,1],"id":"restock","params":[{"in":"body","name":"itemId","wireType":"u64"},{"in":"body","name":"warehouseId","wireType":"u64"},{"in":"body","name":"quantity"}],"path":"/api/admin/restock","reducer":"admin_restock"}},{"do":"expectActionOutcome","outcome":"accepted"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"do":"expectNumber","plus":1,"relativeTo":"purifier-before-control"}],"source":"scenarios/01-admin-write-staff.json","stableKey":"ecommerce.feature.warehouse-admin.admin-write.103a","statedBy":"An administrator can add units to a selected item and warehouse.","withheld":null},{"category":"production","checkGroupId":"warehouse-write-boundary","criterionId":"103b","description":"the server refuses a warehouse write from staff","featureId":103,"featureName":"Only an administrator can restock","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"provenBy":null,"requiresFeatures":["ecommerce.feature.warehouse-admin"],"role":"guarantee","semantics":[{"action":"restock","do":"callAction","input":{"attribute":"data-restock-input","contains":"Air Purifier","testid":"admin-location-row"},"namedAction":{"args":[0,0,1],"id":"restock","params":[{"in":"body","name":"itemId","wireType":"u64"},{"in":"body","name":"warehouseId","wireType":"u64"},{"in":"body","name":"quantity"}],"path":"/api/admin/restock","reducer":"admin_restock"}},{"do":"expectActionOutcome","outcome":"accepted"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"as":"purifier-before-refusal","do":"recordNumber"},{"action":"restock","do":"callAction","from":"admin","input":{"attribute":"data-restock-input","contains":"Air Purifier","testid":"admin-location-row"},"namedAction":{"args":[0,0,1],"id":"restock","params":[{"in":"body","name":"itemId","wireType":"u64"},{"in":"body","name":"warehouseId","wireType":"u64"},{"in":"body","name":"quantity"}],"path":"/api/admin/restock","reducer":"admin_restock"}},{"do":"expectActionOutcome","outcome":"refused","routeProvenBy":"admin"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"do":"expectNumber","plus":0,"relativeTo":"purifier-before-refusal"}],"source":"scenarios/01-admin-write-staff.json","stableKey":"ecommerce.spec.access-control.warehouse-write-boundary.103b","statedBy":"Only administrators can change warehouse stock.","withheld":null},{"category":"production","checkGroupId":"purchase-stock","criterionId":"3b","description":"buying reduces the stock every other client sees, without a reload","featureId":3,"featureName":"Buying","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.live-state","points":2,"provenBy":null,"requiresFeatures":["ecommerce.feature.catalog-items","ecommerce.feature.purchasing"],"role":"guarantee","semantics":[{"do":"expectNumber","equals":100},{"do":"click"},{"do":"expectNumber","equals":99},{"do":"expectNumber","equals":99}],"source":"scenarios/01-buying.json","stableKey":"ecommerce.spec.live-state.purchase-stock.3b","statedBy":"buying an item reduces its stock by one for everyone","withheld":null},{"category":"production","checkGroupId":"cart-boundary","criterionId":"109a","description":"the same cart action run by another customer changes only that customer's cart","featureId":109,"featureName":"A cart is nobody else's business","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"provenBy":null,"requiresFeatures":["ecommerce.feature.cart"],"role":"guarantee","semantics":[{"action":"cart-add","do":"callAction","input":{"attribute":"data-buy-input","contains":"Coffee Grinder","testid":"item-card"},"namedAction":{"args":[0],"id":"cart-add","params":[{"in":"body","name":"itemId","wireType":"u64"}],"path":"/api/cart","reducer":"add_to_cart"}},{"do":"expectActionOutcome","outcome":"accepted"},{"do":"reload"},{"do":"ensureSignedIn","name":"vic"},{"do":"click","ifAvailable":true},{"do":"click","ifAvailable":true},{"do":"click","unlessVisible":"cart-total"},{"do":"reload"},{"do":"ensureSignedIn","name":"wes"},{"do":"click","ifAvailable":true},{"do":"click","ifAvailable":true},{"contains":"Coffee Grinder","count":1,"do":"expect"},{"do":"expectNumber","equals":1},{"do":"click","unlessVisible":"cart-total"},{"contains":"Coffee Grinder","count":1,"do":"expect"},{"do":"expectNumber","equals":1}],"source":"scenarios/01-cart-boundary.json","stableKey":"ecommerce.spec.access-control.cart-boundary.109a","statedBy":"one customer cannot read or change another customer's cart","withheld":null},{"category":"production","checkGroupId":"cart-boundary","criterionId":"109b","description":"a negative quantity is refused and leaves the cart unchanged","featureId":109,"featureName":"A cart is nobody else's business","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":1,"provenBy":null,"requiresFeatures":["ecommerce.feature.cart"],"role":"guarantee","semantics":[{"as":"cart-total-before-invalid","do":"recordNumber"},{"as":"cart-quantity-before-invalid","do":"recordNumber"},{"action":"cart-set-quantity","do":"callAction","input":{"attribute":"data-cart-input","contains":"Coffee Grinder","testid":"cart-item"},"namedAction":{"args":[0,-3],"id":"cart-set-quantity","method":"PATCH","params":[{"in":"path","name":"itemId","placeholder":":itemId","wireType":"u64"},{"in":"body","name":"quantity"}],"path":"/api/cart/:itemId","reducer":"update_cart_quantity"}},{"do":"expectActionOutcome","outcome":"validation-refused"},{"do":"reload"},{"do":"ensureSignedIn","name":"vic"},{"do":"click","ifAvailable":true},{"do":"click","ifAvailable":true},{"do":"click","unlessVisible":"cart-total"},{"do":"expectNumber","plus":0,"relativeTo":"cart-total-before-invalid"},{"do":"expectNumber","plus":0,"relativeTo":"cart-quantity-before-invalid"}],"source":"scenarios/01-cart-boundary.json","stableKey":"ecommerce.spec.access-control.cart-boundary.109b","statedBy":"a request carrying a negative quantity is refused and changes nothing","withheld":null},{"category":"production","checkGroupId":"cart-reload","criterionId":"4b","description":"the cart survives a reload","featureId":4,"featureName":"Cart belongs to the account","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.state-durability","points":1,"provenBy":null,"requiresFeatures":["ecommerce.feature.cart"],"role":"guarantee","semantics":[{"do":"click"},{"do":"click","unlessVisible":"cart-total"},{"contains":"Laptop Stand","do":"expect"},{"do":"reload"},{"do":"ensureSignedIn","name":"omar"},{"do":"click","unlessVisible":"cart-total"},{"contains":"Laptop Stand","do":"expect"}],"source":"scenarios/01-cart.json","stableKey":"ecommerce.spec.state-durability.cart-reload.4b","statedBy":"the cart survives a reload","withheld":null},{"category":"production","checkGroupId":"shared-cart","criterionId":"4c","description":"the same account signed in elsewhere sees one cart, live","featureId":4,"featureName":"Cart belongs to the account","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.live-state","points":2,"provenBy":null,"requiresFeatures":["ecommerce.feature.cart"],"role":"guarantee","semantics":[{"do":"signIn","name":"pia"},{"do":"click","unlessVisible":"cart-total"},{"do":"click"},{"contains":"Induction Cooktop","do":"expect"}],"source":"scenarios/01-cart.json","stableKey":"ecommerce.spec.live-state.shared-cart.4c","statedBy":"the same account signed in twice sees one cart, and a change made in one place appears in the other without a reload","withheld":null},{"category":"feature","checkGroupId":"catalog-ranking","criterionId":"2b","description":"the storefront shows the exact alphabetical top ten before any purchase","featureId":2,"featureName":"Public catalog ranking","note":null,"packId":"ecommerce.feature.catalog-discovery","points":1,"provenBy":null,"role":"feature","semantics":[{"do":"expectSequence","equals":["Air Purifier","Bluetooth Speaker","Coffee Grinder","Desk Lamp","Espresso Machine","Gaming Mouse","Headphones","Induction Cooktop","Keyboard","Laptop Stand"]}],"source":"scenarios/01-catalog-ranking.json","stableKey":"ecommerce.feature.catalog.catalog-ranking.2b","statedBy":"Show the ten most-purchased items and break ties by item name","withheld":null},{"category":"feature","checkGroupId":"catalog-search","criterionId":"2d","description":"case-insensitive partial search finds an item outside the storefront top ten","featureId":2,"featureName":"Public catalog search","note":null,"packId":"ecommerce.feature.catalog-discovery","points":1,"provenBy":null,"role":"feature","semantics":[{"do":"fill","enter":true,"text":"mirrorLESS"},{"contains":"Mirrorless Camera","do":"expect"}],"source":"scenarios/01-catalog-search.json","stableKey":"ecommerce.feature.catalog.catalog-search.2d","statedBy":"Search matches any part of an item name without regard to case across the full catalog","withheld":null},{"category":"feature","checkGroupId":"catalog-values","criterionId":"2a","description":"a signed-out visitor sees the seeded item name, price, and total stock","featureId":2,"featureName":"Public catalog values","note":null,"packId":"ecommerce.feature.catalog-items","points":1,"provenBy":null,"role":"feature","semantics":[{"contains":"Air Purifier","do":"expect"},{"do":"expectNumber","equals":189},{"do":"expectNumber","equals":100}],"source":"scenarios/01-catalog-values.json","stableKey":"ecommerce.feature.catalog.catalog-values.2a","statedBy":"Each item shows its name, price, and total stock","withheld":null},{"category":"production","checkGroupId":"ranking","criterionId":"2c","description":"a purchase moves the bought item to the front of the ranking, live","featureId":2,"featureName":"Storefront is public and live","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.live-state","points":1,"provenBy":null,"requiresFeatures":["ecommerce.feature.catalog-items","ecommerce.feature.purchasing"],"role":"guarantee","semantics":[{"do":"click"},{"do":"expectSequence","equals":["Coffee Grinder","Air Purifier","Bluetooth Speaker","Desk Lamp","Espresso Machine","Gaming Mouse","Headphones","Induction Cooktop","Keyboard","Laptop Stand"]},{"do":"expectAgreement","numeric":true}],"source":"scenarios/01-core.json","stableKey":"ecommerce.spec.live-state.ranking.2c","statedBy":"a purchase immediately changes the ranking for every open client","withheld":null},{"category":"production","checkGroupId":"duplicate-checkout","criterionId":"203a","description":"the same item added from two tabs at once becomes one line of two","featureId":203,"featureName":"One cart, two tabs, one checkout","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.concurrency-safety","points":1,"provenBy":null,"requiresFeatures":["ecommerce.feature.checkout"],"role":"guarantee","semantics":[{"contains":"Gaming Mouse","count":1,"do":"expect"},{"do":"expectNumber","equals":2}],"source":"scenarios/01-duplicate-checkout.json","stableKey":"ecommerce.spec.concurrency-safety.duplicate-checkout.203a","statedBy":"raises its quantity rather than adding a second line","withheld":null},{"category":"production","checkGroupId":"duplicate-checkout","criterionId":"203b","description":"checking the same cart out twice at once produces one order","featureId":203,"featureName":"One cart, two tabs, one checkout","note":"callConcurrently resolves the track's named checkout action through the selected backend adapter and issues it at the same time with tab1 and tab2's own session credentials. The filler prepares the shared Keyboard cart. Native order evidence requires one complete order for that account, the booked price and quantity, a cleared cart, and unchanged prior orders. Checkout can precede warehouse administration, so this check reads no warehouse data and retains its visible stock reduction assertion. The second call may succeed idempotently or deliberately refuse; server errors and no progress fail.","observations":["requested","unmentioned"],"packId":"ecommerce.spec.concurrency-safety","points":1,"provenBy":"The L1 2.3 candidate set binds an exact 203b defect on every reference stack: MongoDB bypasses the atomic cart claim-and-clear, while PostgreSQL and SpacetimeDB leave checked-out cart lines behind. These defects let both named checkout calls reuse the same cart, which the call-outcome and final order assertions are designed to catch. Exact Docker mutation qualification remains the promotion gate.","requiresFeatures":["ecommerce.feature.checkout"],"role":"guarantee","semantics":[{"do":"click"},{"do":"wait"},{"as":"keyboard-before-checkout","do":"recordNumber"},{"account":"{user:twin}","as":"checkout-before","do":"dbRecordCheckout","item":"Keyboard","storage":{"cart":true,"kind":"order-data","warehouses":false}},{"do":"click"},{"do":"wait"},{"account":"{user:twin}","as":"checkout-prepared","do":"dbRecordCheckout","item":"Keyboard","storage":{"cart":true,"kind":"order-data","warehouses":false}},{"action":"checkout","do":"callConcurrently"},{"do":"expectCallOutcomes"},{"before":"checkout-before","do":"dbExpectCheckout","prepared":"checkout-prepared","quantity":1},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"contains":"Keyboard","count":1,"do":"expect"},{"do":"reload"},{"do":"ensureSignedIn","name":"twin"},{"do":"click","ifAvailable":true},{"do":"click","ifAvailable":true},{"do":"expectNumber","plus":-1,"relativeTo":"keyboard-before-checkout"}],"source":"scenarios/01-duplicate-checkout.json","stableKey":"ecommerce.spec.concurrency-safety.duplicate-checkout.203b","statedBy":"checking out twice must not produce two orders","withheld":"The named checkout action has an HTTP route for MongoDB and PostgreSQL and a reducer mapping for SpacetimeDB. The stack adapter issues the corresponding credentialed request for each actor, giving all three stacks the same one-cart, two-call expectation."},{"category":"production","checkGroupId":"external-stock","criterionId":"901a","description":"a direct database write sets Desk Lamp's East stock to 5, and the already-open storefront updates from 100 to 50 without a reload or page action","featureId":901,"featureName":"An open storefront follows a direct database write","note":"This proposed score remains draft until the focused pristine and mutation controls are qualified.","observations":["requested","unmentioned"],"packId":"ecommerce.spec.external-data-sync","points":1,"provenBy":null,"requiresFeatures":["ecommerce.feature.warehouse-admin"],"role":"guarantee","semantics":[{"do":"dbSetStock","item":"Desk Lamp","quantity":5,"warehouse":"East"},{"do":"expectNumber","equals":50}],"source":"scenarios/01-external-live-sync.json","stableKey":"ecommerce.spec.external-data-sync.external-stock.901a","statedBy":"The storefront reflects current database values after changes made outside the application server.","withheld":null},{"category":"production","checkGroupId":"external-stock","criterionId":"901d","description":"while the storefront is offline, a direct database write sets Desk Lamp's East stock to 7; after reconnecting, the same page catches up from 100 to the authoritative total of 52","featureId":901,"featureName":"A reconnecting storefront catches up to an external write","note":"This proposed score remains draft until the focused pristine and mutation controls are qualified.","observations":["requested","unmentioned"],"packId":"ecommerce.spec.external-data-sync","points":1,"provenBy":null,"requiresFeatures":["ecommerce.feature.warehouse-admin"],"role":"guarantee","semantics":[{"do":"setOffline","offline":true},{"do":"dbSetStock","item":"Desk Lamp","quantity":7,"warehouse":"East"},{"do":"setOffline","offline":false},{"do":"expectNumber","equals":52}],"source":"scenarios/01-external-reconnect-sync.json","stableKey":"ecommerce.spec.external-data-sync.external-stock.901d","statedBy":"The storefront reflects current database values after changes made outside the application server.","withheld":null},{"checkGroupId":"external-stock","criterionId":"901b","description":"after a direct database write sets Desk Lamp's East stock to 5, a reload reads the persisted total of 50","featureId":901,"featureName":"A direct database write survives reload","note":"Supporting evidence for 901a rather than a second score. It rules out a page-only patch but has no distinct calibrated failure mode.","observations":["requested","unmentioned"],"packId":"ecommerce.spec.external-data-sync","points":0,"provenBy":null,"requiresFeatures":["ecommerce.feature.warehouse-admin"],"role":"guarantee","semantics":[{"do":"dbSetStock","item":"Desk Lamp","quantity":5,"warehouse":"East"},{"do":"reload"},{"do":"expectNumber","equals":50}],"source":"scenarios/01-external-reload-sync.json","stableKey":"ecommerce.spec.external-data-sync.external-stock.901b","statedBy":"The storefront reflects current database values after changes made outside the application server.","withheld":null},{"category":"production","checkGroupId":"external-stock","criterionId":"901c","description":"a stock correction lands while the app server is stopped, and the already-open storefront shows the authoritative total of 65 after the server returns without a reload","featureId":901,"featureName":"An open storefront catches up after its server restarts","note":"Preserves the previously promoted score while removing its dependency on 901a changing East stock first.","observations":["requested","unmentioned"],"packId":"ecommerce.spec.external-data-sync","points":1,"provenBy":null,"requiresFeatures":["ecommerce.feature.warehouse-admin"],"role":"guarantee","semantics":[{"do":"stopAppServer"},{"do":"dbSetStock","item":"Desk Lamp","quantity":10,"warehouse":"West"},{"do":"startAppServer"},{"do":"expectNumber","equals":65}],"source":"scenarios/01-external-server-restart-sync.json","stableKey":"ecommerce.spec.external-data-sync.external-stock.901c","statedBy":"a restart must end up showing the current numbers once the server is back","withheld":null},{"category":"production","checkGroupId":"last-unit","criterionId":"201a","description":"after six customers try to buy the last three units, each warehouse stores zero stock and all observed clients show zero stock","featureId":201,"featureName":"The last unit is sold once","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.concurrency-safety","points":1,"provenBy":"Prior qualification covers the client observations only. The added stored-stock observations need matching three-stack reference and defect-control evidence before promotion.","requiresFeatures":["ecommerce.feature.catalog-items","ecommerce.feature.purchasing","ecommerce.feature.warehouse-admin"],"role":"guarantee","semantics":[{"do":"dbExpectStock","equals":0,"item":"Air Purifier","warehouse":"East"},{"do":"dbExpectStock","equals":0,"item":"Air Purifier","warehouse":"West"},{"do":"expectNumber","equals":0},{"do":"expectAgreement","numeric":true}],"source":"scenarios/01-last-unit.json","stableKey":"ecommerce.spec.concurrency-safety.last-unit.201a","statedBy":"stock may never go negative, and two customers must never both get the last unit","withheld":null},{"category":"production","checkGroupId":"last-unit","criterionId":"201c","description":"revenue increases by exactly three sales, not six","featureId":201,"featureName":"The last unit is sold once","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.concurrency-safety","points":1,"provenBy":null,"requiresFeatures":["ecommerce.feature.catalog-items","ecommerce.feature.purchasing","ecommerce.feature.warehouse-admin"],"role":"guarantee","semantics":[{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","ifAvailable":true},{"do":"click","unlessVisible":"admin-revenue"},{"do":"expectNumber","plus":567,"relativeTo":"revenue-before-last-unit"}],"source":"scenarios/01-last-unit.json","stableKey":"ecommerce.spec.concurrency-safety.last-unit.201c","statedBy":"stock must never leave a warehouse without a corresponding order","withheld":null},{"category":"production","checkGroupId":"last-unit","criterionId":"201b","description":"the last three units create complete orders for the successful buyers, and all four affordable purchases succeed when stock is sufficient","featureId":201,"featureName":"The last unit is sold once","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.concurrency-safety","points":1,"provenBy":"Draft: native order reconciliation and the sufficient-stock progress case require matching reference and defect controls. This criterion runs after the revenue assertion so its extra purchases cannot alter that assertion's baseline.","requiresFeatures":["ecommerce.feature.catalog-items","ecommerce.feature.purchasing","ecommerce.feature.warehouse-admin"],"role":"guarantee","semantics":[{"before":{"a":"buy-a","b":"buy-b","c":"buy-c","d":"buy-d","e":"buy-e","f":"buy-f"},"do":"dbExpectPurchases","purchases":3},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"contains":"Air Purifier","do":"expectActorsWith","equals":3,"maxEach":1},{"do":"dbSetStock","item":"Air Purifier","quantity":2,"warehouse":"East"},{"do":"dbSetStock","item":"Air Purifier","quantity":2,"warehouse":"West"},{"do":"reload"},{"do":"ensureSignedIn","name":"c1"},{"do":"click","ifAvailable":true},{"account":"{user:c1}","as":"ample-a","do":"dbRecordCheckout","item":"Air Purifier","storage":{"cart":false,"kind":"order-data","warehouses":true}},{"account":"{user:c2}","as":"ample-b","do":"dbRecordCheckout","item":"Air Purifier","storage":{"cart":false,"kind":"order-data","warehouses":true}},{"action":"buy","do":"callConcurrently","from":"a","input":{"attribute":"data-buy-input","contains":"Air Purifier","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"},"requests":4},{"do":"expectCallOutcomes"},{"before":{"a":"ample-a","b":"ample-b"},"do":"dbExpectPurchases","purchases":4}],"source":"scenarios/01-last-unit.json","stableKey":"ecommerce.spec.concurrency-safety.last-unit.201b","statedBy":"two customers must never both get the last unit","withheld":null},{"category":"production","checkGroupId":"order-ownership","criterionId":"106a","description":"a working order history contains the customer's own order and not another customer's order","featureId":106,"featureName":"One customer's orders are not another's","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":1,"provenBy":null,"requiresFeatures":["ecommerce.feature.purchasing"],"role":"guarantee","semantics":[{"do":"click"},{"do":"click"},{"do":"wait"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"contains":"Desk Lamp","count":1,"do":"expect"},{"absent":true,"contains":"Coffee Grinder","do":"expect"}],"source":"scenarios/01-order-ownership.json","stableKey":"ecommerce.spec.access-control.order-ownership.106a","statedBy":"a customer sees only their own orders","withheld":null},{"category":"production","checkGroupId":"purchase-attribution","criterionId":"102a","description":"a direct purchase is attributed to the authenticated caller, not another account","featureId":102,"featureName":"Purchases are attributed to whoever made them","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"provenBy":null,"requiresFeatures":["ecommerce.feature.purchasing"],"role":"guarantee","semantics":[{"action":"buy","do":"callAction","input":{"attribute":"data-buy-input","contains":"Desk Lamp","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"}},{"do":"expectActionOutcome","outcome":"accepted"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"contains":"Coffee Grinder","count":1,"do":"expect"},{"absent":true,"contains":"Desk Lamp","do":"expect"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"contains":"Desk Lamp","count":1,"do":"expect"}],"source":"scenarios/01-purchase-attribution.json","stableKey":"ecommerce.spec.access-control.purchase-attribution.102a","statedBy":"the authenticated caller, not a client-supplied identity, owns the order","withheld":null},{"category":"production","checkGroupId":"purchase-session","criterionId":"101a","description":"a valid direct purchase works for the buyer but is refused without a session","featureId":101,"featureName":"Purchase requires an account","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"provenBy":null,"requiresFeatures":["ecommerce.feature.purchasing"],"role":"guarantee","semantics":[{"action":"buy","authentication":"none","do":"callAction","from":"buyer","input":{"attribute":"data-buy-input","contains":"Bluetooth Speaker","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"}},{"do":"expectActionOutcome","outcome":"refused","routeProvenBy":"buyer"},{"do":"dbExpectStock","item":"Bluetooth Speaker","plus":-1,"relativeTo":"speaker-before-control"}],"source":"scenarios/01-purchase-session.json","stableKey":"ecommerce.spec.access-control.purchase-session.101a","statedBy":"the server refuses a purchase without an authenticated customer","withheld":null},{"category":"feature","checkGroupId":"restock-race","criterionId":"202-control","description":"an uncontended restock of five is stored by the server and shows on the storefront","featureId":202,"featureName":"A restock during a rush is not lost","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.concurrency-safety","points":0,"provenBy":null,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.warehouse-admin"],"role":"guarantee","semantics":[{"do":"dbExpectStock","item":"Bluetooth Speaker","plus":5,"relativeTo":"stored-before-control"},{"do":"expectNumber","plus":5,"relativeTo":"storefront-before"}],"source":"scenarios/01-restock-race.json","stableKey":"ecommerce.spec.concurrency-safety.restock-race.202-control","statedBy":null,"withheld":"The ordinary restock is a setup prerequisite retained when only the race is selected. This zero-point control verifies that setup; it does not add product credit."},{"category":"production","checkGroupId":"restock-race","criterionId":"202a","description":"restocking during purchases preserves stock, complete buyer orders and their warehouse allocations","featureId":202,"featureName":"A restock during a rush is not lost","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.concurrency-safety","points":1,"provenBy":null,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.warehouse-admin"],"role":"guarantee","semantics":[{"as":"stored-before-rush","do":"dbRecordStock","item":"Bluetooth Speaker"},{"do":"fill","text":"5"},{"as":"rush-before","do":"recordNumber"},{"branches":[[{"do":"clickConcurrently"}],[{"do":"click"}]],"do":"race"},{"do":"dbExpectStock","item":"Bluetooth Speaker","plus":2,"relativeTo":"stored-before-rush"},{"atLeast":0,"do":"dbExpectStock","item":"Bluetooth Speaker","warehouse":"East"},{"atLeast":0,"do":"dbExpectStock","item":"Bluetooth Speaker","warehouse":"West"},{"do":"reload"},{"do":"click"},{"do":"expectNumber","plus":2,"relativeTo":"rush-before"},{"do":"ensureSignedIn","name":"r1"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"contains":"Bluetooth Speaker","count":2,"do":"expect"},{"do":"reload"},{"do":"ensureSignedIn","name":"r2"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"contains":"Bluetooth Speaker","count":1,"do":"expect"},{"do":"reload"},{"do":"ensureSignedIn","name":"r3"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"contains":"Bluetooth Speaker","count":1,"do":"expect"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","ifAvailable":true},{"do":"expectNumber","plus":2,"relativeTo":"stored-before-rush"},{"do":"reload"},{"do":"click"},{"do":"expectNumber","plus":2,"relativeTo":"stored-before-rush"},{"do":"ensureSignedIn","name":"r1"},{"account":"{user:r1}","as":"mixed-a","do":"dbRecordCheckout","item":"Bluetooth Speaker","storage":{"cart":false,"kind":"order-data","warehouses":true}},{"account":"{user:r2}","as":"mixed-b","do":"dbRecordCheckout","item":"Bluetooth Speaker","storage":{"cart":false,"kind":"order-data","warehouses":true}},{"account":"{user:r3}","as":"mixed-c","do":"dbRecordCheckout","item":"Bluetooth Speaker","storage":{"cart":false,"kind":"order-data","warehouses":true}},{"action":"buy","alongside":[{"action":"restock","actors":["admin"],"input":{"attribute":"data-restock-input","contains":"Bluetooth Speaker","testid":"admin-location-row"},"namedAction":{"args":[0,0,1],"id":"restock","params":[{"in":"body","name":"itemId","wireType":"u64"},{"in":"body","name":"warehouseId","wireType":"u64"},{"in":"body","name":"quantity"}],"path":"/api/admin/restock","reducer":"admin_restock"},"requests":1}],"do":"callConcurrently","from":"a","input":{"attribute":"data-buy-input","contains":"Bluetooth Speaker","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"},"requests":3},{"accepted":4,"do":"expectCallOutcomes"},{"before":{"a":"mixed-a","b":"mixed-b","c":"mixed-c"},"do":"dbExpectPurchases","purchases":3}],"source":"scenarios/01-restock-race.json","stableKey":"ecommerce.spec.concurrency-safety.restock-race.202a","statedBy":"a restock in one warehouse raises the storefront number live","withheld":null},{"category":"production","checkGroupId":"review-eligibility","criterionId":"108a","description":"someone who never bought the item cannot review it","featureId":108,"featureName":"A review is a claim about a purchase","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"provenBy":null,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.reviews"],"role":"guarantee","semantics":[{"action":"buy","do":"callAction","input":{"attribute":"data-buy-input","contains":"Air Purifier","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"}},{"do":"expectActionOutcome","outcome":"accepted"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"contains":"Air Purifier","do":"expect"},{"do":"click","ifAvailable":true},{"do":"click","ifAvailable":true},{"action":"submitReview","do":"callAction","from":"owner","input":{"attribute":"data-buy-input","contains":"Air Purifier","testid":"item-card"},"namedAction":{"args":[0,4,"eligible review control"],"id":"submitReview","method":"POST","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"},{"in":"body","name":"rating"},{"in":"body","name":"comment"}],"path":"/api/items/:id/reviews","reducer":"submit_review"}},{"do":"expectActionOutcome","outcome":"accepted"},{"do":"openItem","item":"Air Purifier"},{"contains":"eligible review control","do":"expect"},{"action":"submitReview","do":"callAction","from":"owner","input":{"attribute":"data-buy-input","contains":"Air Purifier","testid":"item-card"},"namedAction":{"args":[0,4,"never bought this"],"id":"submitReview","method":"POST","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"},{"in":"body","name":"rating"},{"in":"body","name":"comment"}],"path":"/api/items/:id/reviews","reducer":"submit_review"}},{"do":"expectActionOutcome","outcome":"application-refused","routeProvenBy":"owner"},{"do":"reload"},{"do":"ensureSignedIn","name":"uma"},{"do":"click","ifAvailable":true},{"do":"click","ifAvailable":true},{"do":"openItem","item":"Air Purifier"},{"contains":"eligible review control","do":"expect"},{"absent":true,"contains":"never bought this","do":"expect"}],"source":"scenarios/01-review-eligibility.json","stableKey":"ecommerce.spec.access-control.review-eligibility.108a","statedBy":"the server refuses a review from someone who has never ordered the item","withheld":null},{"category":"production","checkGroupId":"review-eligibility","criterionId":"108b","description":"buying the item earns the right to review it","featureId":108,"featureName":"A review is a claim about a purchase","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":1,"provenBy":null,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.reviews"],"role":"guarantee","semantics":[{"action":"buy","do":"callAction","input":{"attribute":"data-buy-input","contains":"Keyboard","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"}},{"do":"expectActionOutcome","outcome":"accepted"},{"do":"openItem","item":"Keyboard"},{"do":"click","ifAvailable":true,"unlessVisible":"review-rating"},{"do":"fill","text":"4"},{"do":"fill","text":"bought and used it"},{"do":"click"},{"contains":"bought and used it","do":"expect"}],"source":"scenarios/01-review-eligibility.json","stableKey":"ecommerce.spec.access-control.review-eligibility.108b","statedBy":"a customer can review an item they bought","withheld":null},{"category":"production","checkGroupId":"rating","criterionId":"6c","description":"the average rating reflects both reviewers and updates live","featureId":6,"featureName":"Reviews","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.live-state","points":1,"provenBy":null,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.reviews"],"role":"guarantee","semantics":[{"do":"openItem","item":"Gaming Mouse"},{"do":"click","ifAvailable":true,"unlessVisible":"review-rating"},{"do":"fill","text":"4"},{"do":"fill","text":"does the job"},{"do":"click"},{"do":"expectNumber","equals":3},{"do":"expectAgreement","numeric":true}],"source":"scenarios/01-review-rating-live.json","stableKey":"ecommerce.spec.live-state.rating.6c","statedBy":"each item shows its average rating, which updates live as reviews arrive","withheld":null},{"category":"production","checkGroupId":"unique-review","criterionId":"6b","description":"a later review submission does not create a duplicate for the same customer and item","featureId":6,"featureName":"Reviews","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.transactional-integrity","points":1,"provenBy":null,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.reviews"],"role":"guarantee","semantics":[{"do":"click","ifAvailable":true},{"do":"click","ifAvailable":true},{"action":"submitReview","do":"callAction","from":"author","input":{"attribute":"data-buy-input","contains":"Air Purifier","testid":"item-card"},"namedAction":{"args":[0,4,"changed my mind"],"id":"submitReview","method":"POST","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"},{"in":"body","name":"rating"},{"in":"body","name":"comment"}],"path":"/api/items/:id/reviews","reducer":"submit_review"}},{"do":"expectActionOutcome","outcome":"completed"},{"do":"reload"},{"do":"ensureSignedIn","name":"kira"},{"do":"click","ifAvailable":true},{"do":"click","ifAvailable":true},{"do":"openItem","item":"Air Purifier"},{"count":1,"do":"expect"}],"source":"scenarios/01-review-uniqueness.json","stableKey":"ecommerce.spec.transactional-integrity.unique-review.6b","statedBy":"one customer has at most one review per item","withheld":null},{"category":"feature","checkGroupId":"reviews","criterionId":"6a","description":"a customer can review an item and everyone sees it, signed out included","featureId":6,"featureName":"Reviews","note":null,"packId":"ecommerce.feature.reviews","points":2,"provenBy":null,"role":"feature","semantics":[{"do":"openItem","item":"Induction Cooktop"},{"do":"click","ifAvailable":true,"unlessVisible":"review-rating"},{"do":"fill","text":"4"},{"do":"fill","text":"solid mold"},{"do":"click"},{"contains":"solid mold","do":"expect"},{"do":"openItem","item":"Induction Cooktop"},{"contains":"solid mold","do":"expect"}],"source":"scenarios/01-review-visibility.json","stableKey":"ecommerce.feature.reviews.reviews.6a","statedBy":"reviews are visible to everyone, including signed-out visitors","withheld":null},{"category":"production","checkGroupId":"server-price","criterionId":"104a","description":"direct purchases of two differently priced items persist exactly one correctly priced order each","featureId":104,"featureName":"The price is the store's to set","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.transactional-integrity","points":2,"provenBy":null,"requiresFeatures":["ecommerce.feature.purchasing"],"role":"guarantee","semantics":[{"action":"buy","do":"callAction","input":{"attribute":"data-buy-input","contains":"Espresso Machine","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"}},{"do":"expectActionOutcome","outcome":"accepted"},{"action":"buy","do":"callAction","input":{"attribute":"data-buy-input","contains":"Coffee Grinder","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"}},{"do":"expectActionOutcome","outcome":"accepted"},{"do":"freshClient"},{"do":"signIn","name":"oli"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"count":2,"do":"expect"},{"contains":"Espresso Machine","count":1,"do":"expect"},{"do":"expectNumber","equals":449},{"contains":"Coffee Grinder","count":1,"do":"expect"},{"do":"expectNumber","equals":64}],"source":"scenarios/01-server-price.json","stableKey":"ecommerce.spec.transactional-integrity.server-price.104a","statedBy":"the server uses the current stored price when it creates an order","withheld":null},{"category":"production","checkGroupId":"warehouse-area-boundary","criterionId":"7a","description":"the administrator area stays unavailable to other staff","featureId":7,"featureName":"Admin and warehouses","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":1,"provenBy":null,"requiresFeatures":["ecommerce.feature.warehouse-admin"],"role":"guarantee","semantics":[{"do":"expect"},{"do":"click","ifAvailable":true},{"absent":true,"do":"expect"}],"source":"scenarios/01-warehouse-admin-staff.json","stableKey":"ecommerce.spec.access-control.warehouse-area-boundary.7a","statedBy":"Administrators can open the administration area; other staff cannot.","withheld":null},{"category":"feature","checkGroupId":"warehouse-view","criterionId":"7b","description":"admin lists every item, every warehouse, and what each warehouse holds","featureId":7,"featureName":"Admin and warehouses","note":null,"packId":"ecommerce.feature.warehouse-admin","points":1,"provenBy":null,"role":"feature","semantics":[{"count":13,"do":"expect"},{"count":26,"do":"expect"},{"contains":"East","do":"expect"},{"contains":"West","do":"expect"},{"do":"expectNumber","equals":100}],"source":"scenarios/01-warehouse-admin-staff.json","stableKey":"ecommerce.feature.warehouse-admin.warehouse-view.7b","statedBy":"admin lists every item with its stock, every warehouse, and the stock of each item in each warehouse","withheld":null},{"category":"production","checkGroupId":"warehouse-stock","criterionId":"7c","description":"the storefront stock is the sum across warehouses, and a restock raises it live","featureId":7,"featureName":"Warehouse stock stays live","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.live-state","points":2,"provenBy":null,"requiresFeatures":["ecommerce.feature.catalog-items","ecommerce.feature.warehouse-admin"],"role":"guarantee","semantics":[{"do":"fill","text":"25"},{"do":"click"},{"do":"expectNumber","equals":125},{"do":"expectNumber","equals":125}],"source":"scenarios/01-warehouse-stock-live-staff.json","stableKey":"ecommerce.spec.live-state.warehouse-stock.7c","statedBy":"an item's stock on the storefront is the sum of that item's units across all warehouses","withheld":null},{"category":"production","checkGroupId":"cancellation-and-return","criterionId":"3d","description":"cancelling a pending order removes it from the fulfilment queue","featureId":3,"featureName":"Cancellation and fulfilment","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.progression.cancellation-queue-specifications","points":1,"provenBy":null,"requiresFeatures":["ecommerce.l2.order-cancellation-features","ecommerce.progression.fulfilment-queue"],"role":"guarantee","semantics":[{"do":"click"},{"contains":"Coffee Grinder","do":"expect"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click"},{"do":"click"},{"do":"waitUntilAbsent"}],"source":"scenarios/02-cancellation-queue.json","stableKey":"ecommerce.returns-pricing.cancellation-and-return.3d","statedBy":"the order leaves the fulfilment queue","withheld":null},{"category":"production","checkGroupId":"fulfilment-area-boundary","criterionId":"1d","description":"staff and administrators can open fulfilment while customers cannot","featureId":1,"featureName":"Fulfilment area access","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":1,"provenBy":null,"requiresFeatures":["ecommerce.progression.fulfilment-queue"],"role":"guarantee","semantics":[{"do":"click"},{"do":"expect"},{"do":"click"},{"do":"expect"},{"do":"click","ifAvailable":true},{"absent":true,"do":"expect"}],"source":"scenarios/02-fulfilment-access.json","stableKey":"ecommerce.spec.access-control.fulfilment-area-boundary.1d","statedBy":"Customers cannot open the fulfilment area","withheld":null},{"category":"production","checkGroupId":"fulfilment-queue","criterionId":"1a","description":"an order placed by a customer appears in the staff queue without a reload","featureId":1,"featureName":"Live fulfilment queue","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.live-state","points":2,"provenBy":null,"requiresFeatures":["ecommerce.progression.fulfilment-queue"],"role":"guarantee","semantics":[{"as":"depth-before","do":"recordNumber"},{"do":"click"},{"contains":"Desk Lamp","do":"expect"},{"do":"expectNumber","plus":1,"relativeTo":"depth-before"}],"source":"scenarios/02-fulfilment-live.json","stableKey":"ecommerce.spec.live-state.fulfilment-queue.1a","statedBy":"New orders appear in the queue without a reload","withheld":null},{"category":"feature","checkGroupId":"fulfilment-queue","criterionId":"1c","description":"shipping removes the order from the queue and marks the customer's order shipped","featureId":1,"featureName":"Ship a pending order","note":null,"packId":"ecommerce.progression.fulfilment-queue","points":2,"provenBy":null,"requiresFeatures":["ecommerce.feature.purchasing"],"role":"feature","semantics":[{"action":"buy","do":"callAction","input":{"attribute":"data-buy-input","contains":"Keyboard","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"}},{"do":"expectActionOutcome","outcome":"accepted"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"do":"expect","ignoreCase":true,"value":"pending"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"do":"click","ifAvailable":true},{"contains":"Keyboard","do":"expect"},{"do":"click"},{"attribute":"data-submit-state","do":"expect","value":"succeeded"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"do":"click","ifAvailable":true},{"absent":true,"contains":"Keyboard","do":"expect"},{"do":"reload"},{"do":"ensureSignedIn","name":"fq-ship"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"do":"expect","ignoreCase":true,"value":"shipped"}],"source":"scenarios/02-fulfilment-ship.json","stableKey":"ecommerce.operations-access.fulfilment-queue.1c","statedBy":"Staff can mark an order as shipped; show the new status in the fulfilment area and the customer's order history.","withheld":null},{"category":"production","checkGroupId":"refund-accounting","criterionId":"203a","description":"concurrent cancellation restores original stock and the booked amount once, while revenue returns to its prior value","featureId":203,"featureName":"The books still balance once money can flow backwards","note":"Draft: native order, refund and original warehouse allocation evidence supplements the retained revenue assertions. Four calls from two sessions of the owner must cancel once; a repeated call may deliberately refuse or succeed without extra effects. Qualification pending.","observations":["requested","unmentioned"],"packId":"ecommerce.progression.cancellation-accounting-specifications","points":3,"provenBy":null,"requiresFeatures":["ecommerce.l2.order-cancellation-features"],"role":"guarantee","semantics":[{"as":"rev-start","do":"recordNumber"},{"do":"click"},{"do":"wait"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","ifAvailable":true},{"do":"click","unlessVisible":"admin-revenue"},{"do":"expectNumber","plus":42,"relativeTo":"rev-start"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"do":"expect","ignoreCase":true,"value":"pending"},{"account":"{user:books}","as":"cancel-before","do":"dbRecordCheckout","item":"Desk Lamp","storage":{"cart":false,"kind":"order-data","warehouses":true}},{"action":"cancel","do":"callConcurrently","from":"customer","input":{"attribute":"data-cancel-input","contains":"Desk Lamp","testid":"order-item"},"namedAction":{"args":[0],"id":"cancel","params":[{"in":"path","name":"orderId","placeholder":":id","wireType":"u64"}],"path":"/api/orders/:id/cancel","reducer":"cancel_order"},"requests":4},{"do":"expectCallOutcomes"},{"before":"cancel-before","do":"dbExpectCancellation"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","ifAvailable":true},{"do":"click","unlessVisible":"admin-revenue"},{"do":"expectNumber","plus":0,"relativeTo":"rev-start"}],"source":"scenarios/02-invariants.json","stableKey":"ecommerce.returns-pricing.refund-accounting.203a","statedBy":"revenue always equals the sum of orders that are still standing","withheld":null},{"category":"production","checkGroupId":"refund-accounting","criterionId":"203b","description":"a price change does not rewrite revenue already earned","featureId":203,"featureName":"The books still balance once money can flow backwards","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.progression.price-accounting-specifications","points":2,"provenBy":null,"requiresFeatures":["ecommerce.l2.price-history-features"],"role":"guarantee","semantics":[{"as":"history-revenue-before-sale","do":"recordNumber"},{"do":"pressKey","key":"Escape"},{"do":"click"},{"do":"wait"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","ifAvailable":true},{"do":"click","unlessVisible":"admin-revenue"},{"do":"expectNumber","plus":79.5,"relativeTo":"history-revenue-before-sale"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"contains":"Bluetooth Speaker","count":1,"do":"expect"},{"as":"rev-after-sale","do":"recordNumber"},{"do":"fill","text":"5.00"},{"do":"click"},{"do":"wait"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","ifAvailable":true},{"do":"expectNumber","equals":5},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","ifAvailable":true},{"do":"click","unlessVisible":"admin-revenue"},{"do":"expectNumber","plus":0,"relativeTo":"rev-after-sale"}],"source":"scenarios/02-invariants.json","stableKey":"ecommerce.returns-pricing.refund-accounting.203b","statedBy":"changing a price never alters the history, the revenue already recorded","withheld":null},{"category":"production","checkGroupId":"price-history","criterionId":"4b","description":"the new price reaches a signed-out visitor without a reload","featureId":4,"featureName":"Live catalog price","note":null,"packId":"ecommerce.l2.price-history-features","points":2,"provenBy":null,"role":"feature","semantics":[{"atLeast":2,"do":"expectNumber"},{"do":"fill","text":"1.00"},{"do":"click"},{"do":"expectNumber","equals":1}],"source":"scenarios/02-live-price.json","stableKey":"ecommerce.returns-pricing.price-history.4b","statedBy":"the storefront shows the new price immediately, to everyone","withheld":null},{"category":"feature","checkGroupId":"operational-views","criterionId":"5e","description":"the dashboard lists a current low-stock item","featureId":5,"featureName":"The low-stock view","note":null,"packId":"ecommerce.l2.inventory-dashboard","points":1,"provenBy":null,"role":"feature","semantics":[{"contains":"Air Purifier","do":"expect"}],"source":"scenarios/02-low-stock.json","stableKey":"ecommerce.inventory-operations.operational-views.5e","statedBy":"It lists items with 10 units or fewer, most urgent first.","withheld":null},{"category":"production","checkGroupId":"inventory-dashboard","criterionId":"5a","description":"an item falling to ten units or fewer joins the low-stock list, live","featureId":5,"featureName":"The low-stock view","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.live-state","points":3,"provenBy":null,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.l2.inventory-dashboard"],"role":"guarantee","semantics":[{"contains":"Air Purifier","do":"expect"},{"do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click"},{"do":"fill","text":"8"},{"do":"click"},{"do":"waitUntilAbsent"},{"do":"click"},{"contains":"Air Purifier","do":"expect"}],"source":"scenarios/02-low-stock.json","stableKey":"ecommerce.spec.live-state.inventory-dashboard.5a","statedBy":"items enter and leave this list as stock moves, sells, is restocked, cancelled or returned","withheld":null},{"category":"feature","checkGroupId":"operational-views","criterionId":"5d","description":"a signed-out visitor sees a best seller in the recommendations list","featureId":5,"featureName":"Signed-out best sellers","note":null,"packId":"ecommerce.l2.sales-dashboard","points":1,"provenBy":null,"role":"feature","semantics":[{"do":"reload"},{"do":"expectNumber","equals":1}],"source":"scenarios/02-operational-best-sellers.json","stableKey":"ecommerce.inventory-operations.operational-views.5d","statedBy":"Signed-out visitors see best sellers","withheld":null},{"category":"feature","checkGroupId":"operational-views","criterionId":"5f","description":"the dashboard shows category units and revenue","featureId":5,"featureName":"Category sales totals","note":null,"packId":"ecommerce.l2.sales-dashboard","points":1,"provenBy":null,"role":"feature","semantics":[{"do":"click","ifAvailable":true,"unlessVisible":"category-row"},{"as":"audio-core-units","do":"recordNumber"},{"as":"audio-core-revenue","do":"recordNumber"},{"do":"click"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click"},{"do":"click","ifAvailable":true,"unlessVisible":"category-row"},{"do":"expectNumber","plus":1,"relativeTo":"audio-core-units"},{"do":"expectNumber","plus":79.5,"relativeTo":"audio-core-revenue"}],"source":"scenarios/02-operational-category-totals.json","stableKey":"ecommerce.inventory-operations.operational-views.5f","statedBy":"Category totals show units sold and revenue for each category.","withheld":null},{"category":"production","checkGroupId":"sales-dashboard","criterionId":"5b","description":"a purchase updates that category's units and revenue live","featureId":5,"featureName":"Category sales totals","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.live-state","points":3,"provenBy":null,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.l2.sales-dashboard"],"role":"guarantee","semantics":[{"do":"click","ifAvailable":true,"unlessVisible":"category-row"},{"as":"audio-units","do":"recordNumber"},{"as":"audio-revenue","do":"recordNumber"},{"do":"click"},{"do":"expectNumber","plus":1,"relativeTo":"audio-units"},{"do":"expectNumber","plus":79.5,"relativeTo":"audio-revenue"}],"source":"scenarios/02-operational-category-totals.json","stableKey":"ecommerce.spec.live-state.sales-dashboard.5b","statedBy":"Category totals show units sold and revenue for each category","withheld":null},{"category":"feature","checkGroupId":"operational-views","criterionId":"5c","description":"a purchase recommends another item from that category and excludes an item in the cart","featureId":5,"featureName":"Customer recommendations","note":null,"packId":"ecommerce.l2.recommendations","points":2,"provenBy":null,"role":"feature","semantics":[{"do":"click"},{"do":"click","ifAvailable":true},{"do":"click","ifAvailable":true},{"contains":"Headphones","do":"expect"},{"do":"click"},{"do":"waitUntilAbsent"}],"source":"scenarios/02-operational-recommendations.json","stableKey":"ecommerce.inventory-operations.operational-views.5c","statedBy":"Recommend items from categories the customer bought from and exclude items already in the cart","withheld":null},{"category":"production","checkGroupId":"cancellation-and-return","criterionId":"3a","description":"cancelling a pending order restores its stock and revenue","featureId":3,"featureName":"Cancel a pending order","note":null,"packId":"ecommerce.l2.order-cancellation-features","points":2,"provenBy":null,"role":"feature","semantics":[{"as":"revenue-before","do":"recordNumber"},{"as":"stock-before","do":"recordNumber"},{"do":"click"},{"do":"expectNumber","plus":-1,"relativeTo":"stock-before"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","ifAvailable":true},{"do":"expectNumber","plus":64,"relativeTo":"revenue-before"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"do":"expect","ignoreCase":true,"value":"pending"},{"do":"click"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","ifAvailable":true},{"do":"expectNumber","plus":0,"relativeTo":"revenue-before"},{"do":"click","ifAvailable":true},{"do":"click","ifAvailable":true},{"do":"expectNumber","plus":0,"relativeTo":"stock-before"}],"source":"scenarios/02-order-cancellation-core.json","stableKey":"ecommerce.returns-pricing.cancellation-and-return.3a","statedBy":"the stock goes back to the warehouse it came from and revenue falls","withheld":null},{"category":"feature","checkGroupId":"cancellation-and-return","criterionId":"3b","description":"a cancelled order is shown as cancelled in the customer's history","featureId":3,"featureName":"Cancellation history","note":null,"packId":"ecommerce.l2.order-cancellation-features","points":1,"provenBy":null,"role":"feature","semantics":[{"do":"click"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"do":"click"},{"do":"expect","ignoreCase":true,"value":"cancelled"}],"source":"scenarios/02-order-cancellation-history.json","stableKey":"ecommerce.returns-pricing.cancellation-and-return.3b","statedBy":"a customer can cancel an order that has not shipped","withheld":null},{"category":"production","checkGroupId":"price-history","criterionId":"4a","description":"a price change updates the live catalog but leaves the customer's exact paid price unchanged","featureId":4,"featureName":"Prices change, history does not","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.progression.price-history-specifications","points":3,"provenBy":null,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.l2.price-history-features"],"role":"guarantee","semantics":[{"do":"fill","enter":true,"text":"Air Purifier"},{"as":"air-purifier-paid","do":"recordNumber"},{"do":"click"},{"do":"fill","enter":true,"text":"Air Purifier"},{"do":"fill","text":"1.00"},{"do":"click"},{"do":"expectNumber","equals":1},{"do":"reload"},{"do":"ensureSignedIn","name":"history-persisted"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click"},{"do":"expectNumber","plus":0,"relativeTo":"air-purifier-paid"}],"source":"scenarios/02-paid-price-history.json","stableKey":"ecommerce.returns-pricing.price-history.4a","statedBy":"past orders keep the price that was paid","withheld":null},{"category":"feature","checkGroupId":"fulfilment-queue","criterionId":"1b","description":"the queue names the warehouse the order will ship from","featureId":1,"featureName":"Fulfilment queue","note":null,"packId":"ecommerce.progression.fulfilment-queue","points":1,"provenBy":null,"role":"feature","semantics":[{"do":"dbSetStock","item":"Desk Lamp","quantity":0,"warehouse":"West"},{"do":"click"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"do":"click","ifAvailable":true},{"contains":"Desk Lamp","do":"expect"},{"contains":"East","do":"expect"}],"source":"scenarios/02-queue-warehouse.json","stableKey":"ecommerce.operations-access.fulfilment-queue.1b","statedBy":"which warehouse each will ship from","withheld":null},{"category":"production","checkGroupId":"stock-conservation","criterionId":"202b","description":"a sale and its cancellation leave the shelf exactly as they found it","featureId":202,"featureName":"Stock recovery is durable across clients","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.progression.inventory-conservation-specifications","points":2,"provenBy":null,"requiresFeatures":["ecommerce.l2.order-cancellation-features"],"role":"guarantee","semantics":[{"as":"east-before-cancel-202b","do":"dbRecordStock","item":"Induction Cooktop","warehouse":"East"},{"as":"west-before-cancel-202b","do":"dbRecordStock","item":"Induction Cooktop","warehouse":"West"},{"as":"stored-before-cancel-202b","do":"dbRecordStock","item":"Induction Cooktop"},{"as":"cancel-stock-before","do":"recordNumber"},{"do":"click"},{"do":"expectNumber","plus":-1,"relativeTo":"cancel-stock-before"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"contains":"Induction Cooktop","count":1,"do":"expect"},{"do":"dbExpectStock","item":"Induction Cooktop","plus":-1,"relativeTo":"stored-before-cancel-202b"},{"do":"click"},{"do":"click","ifAvailable":true},{"do":"click","ifAvailable":true},{"do":"expectNumber","plus":0,"relativeTo":"cancel-stock-before"},{"do":"dbExpectStock","item":"Induction Cooktop","plus":0,"relativeTo":"stored-before-cancel-202b"},{"do":"dbExpectStock","item":"Induction Cooktop","plus":0,"relativeTo":"east-before-cancel-202b","warehouse":"East"},{"do":"dbExpectStock","item":"Induction Cooktop","plus":0,"relativeTo":"west-before-cancel-202b","warehouse":"West"}],"source":"scenarios/02-self-contained.json","stableKey":"ecommerce.inventory-operations.stock-conservation.202b","statedBy":"the stock goes back to the warehouse it came from","withheld":null},{"category":"production","checkGroupId":"stock-conservation","criterionId":"202c","description":"a fresh client sees the restored total after a sale is cancelled","featureId":202,"featureName":"Stock recovery is durable across clients","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.progression.inventory-conservation-specifications","points":1,"provenBy":null,"requiresFeatures":["ecommerce.l2.order-cancellation-features"],"role":"guarantee","semantics":[{"as":"east-before-cancel-202c","do":"dbRecordStock","item":"Headphones","warehouse":"East"},{"as":"west-before-cancel-202c","do":"dbRecordStock","item":"Headphones","warehouse":"West"},{"as":"stored-before-cancel-202c","do":"dbRecordStock","item":"Headphones"},{"as":"fresh-stock-before","do":"recordNumber"},{"do":"click"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"contains":"Headphones","count":1,"do":"expect"},{"do":"dbExpectStock","item":"Headphones","plus":-1,"relativeTo":"stored-before-cancel-202c"},{"do":"click"},{"do":"freshClient"},{"do":"expectNumber","plus":0,"relativeTo":"fresh-stock-before"},{"do":"dbExpectStock","item":"Headphones","plus":0,"relativeTo":"stored-before-cancel-202c"},{"do":"dbExpectStock","item":"Headphones","plus":0,"relativeTo":"east-before-cancel-202c","warehouse":"East"},{"do":"dbExpectStock","item":"Headphones","plus":0,"relativeTo":"west-before-cancel-202c","warehouse":"West"}],"source":"scenarios/02-self-contained.json","stableKey":"ecommerce.inventory-operations.stock-conservation.202c","statedBy":"every one of these numbers is the same for every person looking at it","withheld":null},{"category":"production","checkGroupId":"operator-authorization","criterionId":"201c","description":"the server refuses a customer's direct attempt to ship their own pending order","featureId":201,"featureName":"Shipping requires an operator","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.progression.operations-access-specifications","points":2,"provenBy":null,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.progression.fulfilment-queue"],"role":"guarantee","semantics":[{"do":"click","ifAvailable":true},{"do":"click","ifAvailable":true},{"do":"click"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"contains":"Coffee Grinder","count":1,"do":"expect"},{"action":"ship","do":"callAction","from":"customer","input":{"attribute":"data-ship-input","contains":"Coffee Grinder","testid":"order-item"},"namedAction":{"args":[0],"id":"ship","params":[{"in":"body","name":"orderId","wireType":"u64"}],"path":"/api/fulfilment/ship","reducer":"ship_order"}},{"do":"expectActionOutcome","outcome":"accepted"},{"do":"reload"},{"do":"ensureSignedIn","name":"direct-notstaff"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"do":"expect","ignoreCase":true,"value":"shipped"},{"action":"ship","do":"callAction","input":{"attribute":"data-ship-input","contains":"Laptop Stand","testid":"order-item"},"namedAction":{"args":[0],"id":"ship","params":[{"in":"body","name":"orderId","wireType":"u64"}],"path":"/api/fulfilment/ship","reducer":"ship_order"}},{"do":"expectActionOutcome","outcome":"refused","routeProvenBy":"staff"},{"do":"reload"},{"do":"ensureSignedIn","name":"direct-notstaff"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"do":"expect","ignoreCase":true,"value":"pending"}],"source":"scenarios/02-server-actions.json","stableKey":"ecommerce.operations-access.operator-authorization.201c","statedBy":"Staff mark an order shipped","withheld":null},{"category":"production","checkGroupId":"stock-conservation","criterionId":"202d","description":"a direct transfer racing a direct purchase leaves the exact starting total minus the sold unit","featureId":202,"featureName":"Stock is conserved while operations overlap","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.progression.inventory-conservation-specifications","points":2,"provenBy":null,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.l2.stock-transfers-features"],"role":"guarantee","semantics":[{"do":"dbExpectStock","equals":60,"item":"Headphones","warehouse":"East"},{"do":"dbExpectStock","equals":40,"item":"Headphones","warehouse":"West"},{"as":"direct-race-stock-before","do":"dbRecordStock","item":"Headphones"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","ifAvailable":true},{"do":"reload"},{"do":"ensureSignedIn","name":"direct-conserve"},{"do":"fill","text":"East"},{"do":"fill","text":"West"},{"do":"fill","text":"25"},{"branches":[[{"action":"transfer","do":"callAction","input":{"attribute":"data-transfer-input","contains":"Headphones","testid":"admin-item-row"},"namedAction":{"args":[0,0,0,25],"id":"transfer","params":[{"in":"body","name":"itemId","wireType":"u64"},{"in":"body","name":"fromWarehouseId","wireType":"u64"},{"in":"body","name":"toWarehouseId","wireType":"u64"},{"in":"body","name":"quantity"}],"path":"/api/admin/transfer","reducer":"admin_transfer_stock"}}],[{"action":"buy","do":"callAction","input":{"attribute":"data-buy-input","contains":"Headphones","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"}}]],"do":"race"},{"do":"expectActionOutcome","outcome":"accepted"},{"do":"expectActionOutcome","outcome":"accepted"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","ifAvailable":true},{"do":"expectNumber","plus":-1,"relativeTo":"direct-race-stock-before"},{"do":"reload"},{"do":"ensureSignedIn","name":"direct-conserve"},{"do":"click","ifAvailable":true},{"do":"click","ifAvailable":true},{"do":"expectNumber","plus":-1,"relativeTo":"direct-race-stock-before"},{"atLeast":34,"atMost":35,"do":"dbExpectStock","item":"Headphones","warehouse":"East"},{"atLeast":64,"atMost":65,"do":"dbExpectStock","item":"Headphones","warehouse":"West"},{"do":"dbExpectStock","item":"Headphones","plus":-1,"relativeTo":"direct-race-stock-before"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"contains":"Headphones","count":1,"do":"expect"}],"source":"scenarios/02-server-actions.json","stableKey":"ecommerce.inventory-operations.stock-conservation.202d","statedBy":"a transfer moves stock, it does not create or destroy it","withheld":null},{"category":"production","checkGroupId":"order-owner","criterionId":"204a","description":"the server refuses one customer trying to cancel another customer's still-pending order","featureId":204,"featureName":"An order belongs to the person who placed it","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.progression.operations-access-specifications","points":2,"provenBy":null,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.l2.order-cancellation-features"],"role":"guarantee","semantics":[{"action":"cancel","do":"callAction","input":{"attribute":"data-cancel-input","contains":"Desk Lamp","testid":"order-item"},"namedAction":{"args":[0],"id":"cancel","params":[{"in":"path","name":"orderId","placeholder":":id","wireType":"u64"}],"path":"/api/orders/:id/cancel","reducer":"cancel_order"}},{"do":"expectActionOutcome","outcome":"accepted"},{"action":"cancel","do":"callAction","from":"owner","input":{"attribute":"data-cancel-input","contains":"Keyboard","testid":"order-item"},"namedAction":{"args":[0],"id":"cancel","params":[{"in":"path","name":"orderId","placeholder":":id","wireType":"u64"}],"path":"/api/orders/:id/cancel","reducer":"cancel_order"}},{"do":"expectActionOutcome","outcome":"refused","routeProvenBy":"owner"},{"do":"reload"},{"do":"ensureSignedIn","name":"direct-owner"},{"do":"click","ifAvailable":true},{"do":"click","unlessVisible":"order-item"},{"do":"expect","ignoreCase":true,"value":"pending"}],"source":"scenarios/02-server-actions.json","stableKey":"ecommerce.operations-access.order-owner.204a","statedBy":"A customer can cancel an order that has not shipped","withheld":null},{"category":"production","checkGroupId":"warehouse-transfer","criterionId":"2a","description":"a transfer decreases the source, increases the destination, and preserves the item's exact total","featureId":2,"featureName":"Moving stock between warehouses","note":null,"packId":"ecommerce.l2.stock-transfers-features","points":3,"provenBy":null,"role":"feature","semantics":[{"as":"product-East","do":"dbRecordStock","item":"Headphones","warehouse":"East"},{"as":"product-West","do":"dbRecordStock","item":"Headphones","warehouse":"West"},{"as":"transfer-item-before","do":"recordNumber"},{"contains":"East","count":1,"do":"expect"},{"as":"transfer-east-before","do":"recordNumber"},{"contains":"West","count":1,"do":"expect"},{"as":"transfer-west-before","do":"recordNumber"},{"do":"fill","text":"East"},{"do":"fill","text":"West"},{"do":"fill","text":"10"},{"do":"click"},{"contains":"East","count":1,"do":"expect"},{"do":"dbExpectStock","item":"Headphones","plus":-10,"relativeTo":"product-East","warehouse":"East"},{"do":"dbExpectStock","item":"Headphones","plus":10,"relativeTo":"product-West","warehouse":"West"},{"do":"expectNumber","plus":-10,"relativeTo":"transfer-east-before"},{"contains":"West","count":1,"do":"expect"},{"do":"expectNumber","plus":10,"relativeTo":"transfer-west-before"},{"do":"expectNumber","plus":0,"relativeTo":"transfer-item-before"}],"source":"scenarios/02-strengthened.json","stableKey":"ecommerce.inventory-operations.warehouse-transfer.2a","statedBy":"a transfer moves stock, it does not create or destroy it","withheld":null},{"category":"production","checkGroupId":"operator-authorization","criterionId":"201a","description":"the server refuses a customer's direct transfer and neither warehouse nor the item total changes","featureId":201,"featureName":"Operating the store requires authorization","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.progression.operations-access-specifications","points":2,"provenBy":null,"requiresFeatures":["ecommerce.l2.stock-transfers-features"],"role":"guarantee","semantics":[{"as":"authorized-transfer-east","do":"dbRecordStock","item":"Headphones","warehouse":"East"},{"as":"authorized-transfer-west","do":"dbRecordStock","item":"Headphones","warehouse":"West"},{"do":"fill","text":"East"},{"do":"fill","text":"West"},{"do":"fill","text":"25"},{"action":"transfer","do":"callAction","input":{"attribute":"data-transfer-input","contains":"Headphones","testid":"admin-item-row"},"namedAction":{"args":[0,0,0,25],"id":"transfer","params":[{"in":"body","name":"itemId","wireType":"u64"},{"in":"body","name":"fromWarehouseId","wireType":"u64"},{"in":"body","name":"toWarehouseId","wireType":"u64"},{"in":"body","name":"quantity"}],"path":"/api/admin/transfer","reducer":"admin_transfer_stock"}},{"do":"expectActionOutcome","outcome":"accepted"},{"do":"dbExpectStock","item":"Headphones","plus":-25,"relativeTo":"authorized-transfer-east","warehouse":"East"},{"do":"dbExpectStock","item":"Headphones","plus":25,"relativeTo":"authorized-transfer-west","warehouse":"West"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","ifAvailable":true},{"do":"reload"},{"do":"ensureSignedIn","name":"not-operator"},{"as":"unauthorized-item-before","do":"recordNumber"},{"contains":"East","count":1,"do":"expect"},{"as":"unauthorized-east-before","do":"recordNumber"},{"contains":"West","count":1,"do":"expect"},{"as":"unauthorized-west-before","do":"recordNumber"},{"do":"fill","text":"East"},{"do":"fill","text":"West"},{"as":"refused-East","do":"dbRecordStock","item":"Headphones","warehouse":"East"},{"as":"refused-West","do":"dbRecordStock","item":"Headphones","warehouse":"West"},{"action":"transfer","do":"callAction","from":"admin","input":{"attribute":"data-transfer-input","contains":"Headphones","testid":"admin-item-row"},"namedAction":{"args":[0,0,0,25],"id":"transfer","params":[{"in":"body","name":"itemId","wireType":"u64"},{"in":"body","name":"fromWarehouseId","wireType":"u64"},{"in":"body","name":"toWarehouseId","wireType":"u64"},{"in":"body","name":"quantity"}],"path":"/api/admin/transfer","reducer":"admin_transfer_stock"}},{"do":"expectActionOutcome","outcome":"refused","routeProvenBy":"admin"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","ifAvailable":true},{"do":"reload"},{"do":"ensureSignedIn","name":"not-operator"},{"contains":"East","count":1,"do":"expect"},{"do":"dbExpectStock","item":"Headphones","plus":0,"relativeTo":"refused-East","warehouse":"East"},{"do":"dbExpectStock","item":"Headphones","plus":0,"relativeTo":"refused-West","warehouse":"West"},{"do":"expectNumber","plus":0,"relativeTo":"unauthorized-east-before"},{"contains":"West","count":1,"do":"expect"},{"do":"expectNumber","plus":0,"relativeTo":"unauthorized-west-before"},{"do":"expectNumber","plus":0,"relativeTo":"unauthorized-item-before"}],"source":"scenarios/02-strengthened.json","stableKey":"ecommerce.operations-access.operator-authorization.201a","statedBy":"An admin can transfer a number of units of an item from one warehouse to another","withheld":null},{"category":"production","checkGroupId":"operator-authorization","criterionId":"201b","description":"the server refuses a customer's direct price change and the last accepted price remains exact","featureId":201,"featureName":"Operating the store requires authorization","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.progression.operations-access-specifications","points":2,"provenBy":null,"requiresFeatures":["ecommerce.l2.price-history-features"],"role":"guarantee","semantics":[{"do":"fill","text":"77.00"},{"action":"price","do":"callAction","input":{"attribute":"data-price-input","contains":"Gaming Mouse","testid":"admin-item-row"},"namedAction":{"args":[0,1],"id":"price","params":[{"in":"body","name":"itemId","wireType":"u64"},{"in":"body","name":"price"}],"path":"/api/admin/price","reducer":"admin_change_price"}},{"do":"expectActionOutcome","outcome":"accepted"},{"do":"reload"},{"do":"ensureSignedIn","name":"not-operator"},{"do":"expectNumber","equals":77},{"do":"fill","text":"1.00"},{"action":"price","do":"callAction","from":"admin","input":{"attribute":"data-price-input","contains":"Gaming Mouse","testid":"admin-item-row"},"namedAction":{"args":[0,1],"id":"price","params":[{"in":"body","name":"itemId","wireType":"u64"},{"in":"body","name":"price"}],"path":"/api/admin/price","reducer":"admin_change_price"}},{"do":"expectActionOutcome","outcome":"refused","routeProvenBy":"admin"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","ifAvailable":true},{"do":"reload"},{"do":"ensureSignedIn","name":"not-operator"},{"do":"expectNumber","equals":77}],"source":"scenarios/02-strengthened.json","stableKey":"ecommerce.operations-access.operator-authorization.201b","statedBy":"an admin can change an item's price","withheld":null},{"category":"production","checkGroupId":"stock-conservation","criterionId":"202a","description":"a transfer decreases East, increases West, and leaves the item's exact total unchanged","featureId":202,"featureName":"Stock is conserved however it moves","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.progression.inventory-conservation-specifications","points":2,"provenBy":null,"requiresFeatures":["ecommerce.l2.stock-transfers-features"],"role":"guarantee","semantics":[{"as":"product-East","do":"dbRecordStock","item":"Espresso Machine","warehouse":"East"},{"as":"product-West","do":"dbRecordStock","item":"Espresso Machine","warehouse":"West"},{"as":"conservation-item-before","do":"recordNumber"},{"contains":"East","count":1,"do":"expect"},{"as":"conservation-east-before","do":"recordNumber"},{"contains":"West","count":1,"do":"expect"},{"as":"conservation-west-before","do":"recordNumber"},{"do":"fill","text":"East"},{"do":"fill","text":"West"},{"do":"fill","text":"17"},{"do":"click"},{"contains":"East","count":1,"do":"expect"},{"do":"dbExpectStock","item":"Espresso Machine","plus":-17,"relativeTo":"product-East","warehouse":"East"},{"do":"dbExpectStock","item":"Espresso Machine","plus":17,"relativeTo":"product-West","warehouse":"West"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","unlessVisible":"admin-revenue"},{"do":"expectNumber","plus":-17,"relativeTo":"conservation-east-before"},{"contains":"West","count":1,"do":"expect"},{"do":"expectNumber","plus":17,"relativeTo":"conservation-west-before"},{"do":"expectNumber","plus":0,"relativeTo":"conservation-item-before"}],"source":"scenarios/02-strengthened.json","stableKey":"ecommerce.inventory-operations.stock-conservation.202a","statedBy":"a transfer moves stock, it does not create or destroy it","withheld":null},{"category":"production","checkGroupId":"stock-transfer-overdraw","criterionId":"2c","description":"a transfer that would overdraw a warehouse is refused and changes neither warehouse nor the item total","featureId":2,"featureName":"Moving stock between warehouses","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.transactional-integrity","points":2,"provenBy":null,"requiresFeatures":["ecommerce.l2.stock-transfers-features"],"role":"guarantee","semantics":[{"as":"product-East","do":"dbRecordStock","item":"Headphones","warehouse":"East"},{"as":"product-West","do":"dbRecordStock","item":"Headphones","warehouse":"West"},{"as":"overdraw-item-before","do":"recordNumber"},{"as":"overdraw-east-before","do":"recordNumber"},{"as":"overdraw-west-before","do":"recordNumber"},{"do":"fill","text":"East"},{"do":"fill","text":"West"},{"do":"fill","text":"99999"},{"do":"click"},{"do":"expect"},{"do":"dbExpectStock","item":"Headphones","plus":0,"relativeTo":"product-East","warehouse":"East"},{"do":"dbExpectStock","item":"Headphones","plus":0,"relativeTo":"product-West","warehouse":"West"},{"do":"expectNumber","plus":0,"relativeTo":"overdraw-east-before"},{"do":"expectNumber","plus":0,"relativeTo":"overdraw-west-before"},{"do":"expectNumber","plus":0,"relativeTo":"overdraw-item-before"}],"source":"scenarios/02-transfer-overdraw.json","stableKey":"ecommerce.spec.transactional-integrity.stock-transfer-overdraw.2c","statedBy":"a transfer that would leave a warehouse short is refused and changes nothing","withheld":null},{"category":"production","checkGroupId":"stock-transfers","criterionId":"2b","description":"both warehouse totals move live and in opposite directions as stock is transferred","featureId":2,"featureName":"Warehouse totals","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.live-state","points":2,"provenBy":null,"requiresFeatures":["ecommerce.l2.stock-transfers-features"],"role":"guarantee","semantics":[{"as":"product-East","do":"dbRecordStock","item":"Headphones","warehouse":"East"},{"as":"product-West","do":"dbRecordStock","item":"Headphones","warehouse":"West"},{"contains":"East","count":1,"do":"expect"},{"as":"warehouse-east-before","do":"recordNumber"},{"contains":"West","count":1,"do":"expect"},{"as":"warehouse-west-before","do":"recordNumber"},{"do":"fill","text":"East"},{"do":"fill","text":"West"},{"do":"fill","text":"10"},{"do":"click"},{"contains":"East","count":1,"do":"expect"},{"do":"expectNumber","plus":-10,"relativeTo":"warehouse-east-before"},{"contains":"West","count":1,"do":"expect"},{"do":"expectNumber","plus":10,"relativeTo":"warehouse-west-before"},{"do":"dbExpectStock","item":"Headphones","plus":-10,"relativeTo":"product-East","warehouse":"East"},{"do":"dbExpectStock","item":"Headphones","plus":10,"relativeTo":"product-West","warehouse":"West"}],"source":"scenarios/02-transfer-totals.json","stableKey":"ecommerce.spec.live-state.stock-transfers.2b","statedBy":"the per-warehouse numbers staff and admins see both move at once","withheld":null},{"category":"production","checkGroupId":"cart-expiration","criterionId":"304a","description":"an inactive cart expires without a browser, releases stock, and returns empty","featureId":304,"featureName":"An inactive cart expires","note":null,"packId":"ecommerce.l3.cart-expiration-features","points":4,"provenBy":null,"role":"feature","semantics":[{"do":"wait"},{"do":"reload"},{"do":"expectNumber","plus":0,"relativeTo":"before"},{"do":"openClient"},{"do":"expect"},{"do":"expectNumber","equals":0}],"source":"scenarios/03-cart-expiration.json","stableKey":"ecommerce.l3.cart-expiration.cart-expiration.304a","statedBy":"A cart with no activity for five minutes expires and releases its reservations.","withheld":null},{"category":"production","checkGroupId":"scheduled-work-access","criterionId":"317a","description":"the server refuses customer scheduling and cancellation of restocks","featureId":317,"featureName":"Customers cannot manage scheduled restocks","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.l3.deferred-access-specifications","points":3,"provenBy":null,"requiresFeatures":["ecommerce.l3.scheduled-restocks-features"],"role":"guarantee","semantics":[{"do":"fill","text":"Webcam"},{"do":"fill","text":"West"},{"do":"fill","text":"3"},{"do":"fill","text":"180"},{"action":"scheduleRestock","authentication":"actor","do":"callAction","from":"admin","input":{"attribute":"data-action-input","testid":"schedule-restock-submit"},"namedAction":{"args":["","",0,0],"id":"scheduleRestock","method":"POST","params":[{"in":"body","name":"item"},{"in":"body","name":"warehouse"},{"in":"body","name":"quantity"},{"in":"body","name":"delaySeconds"}],"path":"/api/admin/scheduled-restocks","reducer":"schedule_restock"}},{"do":"expectActionOutcome","outcome":"refused"},{"do":"replayAs","from":"admin","match":"DELETE","namedAction":{"args":[0],"id":"cancelScheduledRestock","method":"DELETE","params":[{"in":"path","name":"restockId","placeholder":"{restockId}","wireType":"u64"}],"path":"/api/admin/scheduled-restocks/{restockId}","reducer":"cancel_scheduled_restock"},"namedTarget":{"attribute":"data-entity-id","testid":"pending-restock-item","valueType":"string"}},{"do":"expectReplayRejected"},{"count":1,"do":"expect"},{"do":"click"}],"source":"scenarios/03-deferred-access.json","stableKey":"ecommerce.l3.deferred-access.scheduled-work-access.317a","statedBy":"Only an admin can schedule or cancel a restock.","withheld":null},{"category":"production","checkGroupId":"restart-survival","criterionId":"311a","description":"a restock scheduled before restart still applies","featureId":311,"featureName":"A scheduled restock survives restart","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.l3.deferred-durability-specifications","points":4,"provenBy":null,"requiresFeatures":["ecommerce.l3.scheduled-restocks-features"],"role":"guarantee","semantics":[{"do":"dbExpectStock","item":"Air Purifier","plus":5,"relativeTo":"before"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","ifAvailable":true},{"do":"click","ifAvailable":true},{"do":"expect"},{"absent":true,"do":"expect"}],"source":"scenarios/03-deferred-durability.json","stableKey":"ecommerce.l3.deferred-durability.restart-survival.311a","statedBy":"Pending restocks survive a backend restart.","withheld":null},{"category":"production","checkGroupId":"restart-survival","criterionId":"314a","description":"a reservation pending before restart still expires and returns stock","featureId":314,"featureName":"A reservation survives restart","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.l3.deferred-durability-specifications","points":4,"provenBy":null,"requiresFeatures":["ecommerce.l3.reservations-features"],"role":"guarantee","semantics":[{"atMost":70000,"do":"expectElapsed","since":"pending-314"},{"do":"reload"},{"atMost":70000,"do":"expectElapsed","since":"pending-314"},{"do":"expectNumber","plus":-1,"relativeTo":"before"},{"atMost":70000,"do":"expectElapsed","since":"pending-314"},{"do":"wait","since":"pending-314-accepted"},{"do":"reload"},{"do":"expectNumber","plus":0,"relativeTo":"before"},{"do":"reload"},{"do":"ensureSignedIn","name":"durable-reservation"},{"do":"click","unlessVisible":"cart-item"},{"do":"expect"}],"source":"scenarios/03-deferred-durability.json","stableKey":"ecommerce.l3.deferred-durability.restart-survival.314a","statedBy":"Pending reservations survive a backend restart.","withheld":null},{"category":"production","checkGroupId":"restart-survival","criterionId":"315a","description":"an order shipped before restart still becomes delivered","featureId":315,"featureName":"An order transition survives restart","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.l3.deferred-durability-specifications","points":4,"provenBy":null,"requiresFeatures":["ecommerce.l3.order-delivery-features"],"role":"guarantee","semantics":[{"do":"wait","since":"delivery-start-accepted"},{"do":"reload"},{"do":"ensureSignedIn","name":"durable-delivery"},{"do":"click","ifAvailable":true},{"do":"click","unlessVisible":"order-item"},{"do":"expect","ignoreCase":true,"value":"delivered"}],"source":"scenarios/03-deferred-durability.json","stableKey":"ecommerce.l3.deferred-durability.restart-survival.315a","statedBy":"Pending order delivery survives a backend restart.","withheld":null},{"category":"production","checkGroupId":"restart-survival","criterionId":"316a","description":"a cart survives restart and expires near its original five-minute deadline","featureId":316,"featureName":"Cart expiration survives restart","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.l3.deferred-durability-specifications","points":4,"provenBy":null,"requiresFeatures":["ecommerce.l3.cart-expiration-features"],"role":"guarantee","semantics":[{"atMost":250000,"do":"expectElapsed","since":"pending-316"},{"do":"reload"},{"do":"ensureSignedIn","name":"durable-cart"},{"do":"click","ifAvailable":true},{"do":"click","unlessVisible":"cart-item"},{"atMost":250000,"do":"expectElapsed","since":"pending-316"},{"do":"expectNumber","equals":1},{"atMost":250000,"do":"expectElapsed","since":"pending-316"},{"do":"wait","since":"pending-316-accepted"},{"do":"reload"},{"do":"ensureSignedIn","name":"durable-cart"},{"do":"click"},{"do":"expectNumber","equals":0},{"do":"expect"},{"do":"reload"},{"do":"expectNumber","plus":0,"relativeTo":"before"}],"source":"scenarios/03-deferred-durability.json","stableKey":"ecommerce.l3.deferred-durability.restart-survival.316a","statedBy":"Pending cart expiration survives a backend restart.","withheld":null},{"category":"production","checkGroupId":"exactly-once","criterionId":"311a","description":"restart cannot replay a completed restock","featureId":311,"featureName":"A restock applies once","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.l3.deferred-integrity-specifications","points":3,"provenBy":null,"requiresFeatures":["ecommerce.l3.scheduled-restocks-features"],"role":"guarantee","semantics":[{"do":"reload"},{"do":"dbExpectStock","item":"Air Purifier","plus":5,"relativeTo":"before"},{"do":"restartBackend"},{"do":"reload"},{"do":"wait"},{"do":"dbExpectStock","item":"Air Purifier","plus":5,"relativeTo":"before"}],"source":"scenarios/03-deferred-integrity.json","stableKey":"ecommerce.l3.deferred-integrity.exactly-once.311a","statedBy":"Restarting the backend cannot apply a restock more than once.","withheld":null},{"category":"production","checkGroupId":"exactly-once","criterionId":"312a","description":"restart leaves one delivered order record","featureId":312,"featureName":"Delivery applies once","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.l3.deferred-integrity-specifications","points":3,"provenBy":null,"requiresFeatures":["ecommerce.l3.order-delivery-features"],"role":"guarantee","semantics":[{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"do":"click","ifAvailable":true},{"contains":"Desk Lamp","count":1,"do":"expect"},{"do":"expect","ignoreCase":true,"value":"delivered"}],"source":"scenarios/03-deferred-integrity.json","stableKey":"ecommerce.l3.deferred-integrity.exactly-once.312a","statedBy":"A delivered order is not duplicated by a backend restart.","withheld":null},{"category":"production","checkGroupId":"stock-conservation","criterionId":"313a","description":"expiry returns exactly the unit reserved","featureId":313,"featureName":"Reservation expiry conserves stock","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.l3.deferred-integrity-specifications","points":3,"provenBy":null,"requiresFeatures":["ecommerce.l3.reservations-features"],"role":"guarantee","semantics":[{"do":"wait"},{"do":"reload"},{"do":"expectNumber","plus":0,"relativeTo":"before"}],"source":"scenarios/03-deferred-integrity.json","stableKey":"ecommerce.l3.deferred-integrity.stock-conservation.313a","statedBy":"Reservation expiry returns exactly the stock that the reservation took.","withheld":null},{"category":"production","checkGroupId":"stock-conservation","criterionId":"314a","description":"checkout does not decrement stock after the reservation already did","featureId":314,"featureName":"Checkout conserves reserved stock","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.l3.deferred-integrity-specifications","points":3,"provenBy":null,"requiresFeatures":["ecommerce.l3.reservations-features"],"role":"guarantee","semantics":[{"do":"click"},{"do":"expectNumber","equals":0},{"do":"reload"},{"do":"ensureSignedIn","name":"conserve-checkout"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click"},{"contains":"Headphones","do":"expectElementCount","equals":1},{"do":"reload"},{"do":"expectNumber","plus":-1,"relativeTo":"before"}],"source":"scenarios/03-deferred-integrity.json","stableKey":"ecommerce.l3.deferred-integrity.stock-conservation.314a","statedBy":"Checkout does not take reserved stock twice.","withheld":null},{"category":"production","checkGroupId":"order-delivery","criterionId":"303a","description":"a shipped order becomes delivered in customer and staff views","featureId":303,"featureName":"A shipped order becomes delivered","note":null,"packId":"ecommerce.l3.order-delivery-features","points":3,"provenBy":null,"role":"feature","semantics":[{"do":"wait"},{"do":"reload"},{"do":"ensureSignedIn","name":"delivery-live"},{"do":"click","ifAvailable":true},{"do":"click","unlessVisible":"order-item"},{"do":"expect","ignoreCase":true,"value":"delivered"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"do":"click","ifAvailable":true},{"do":"click","unlessVisible":"completed-order-item"},{"do":"expect","ignoreCase":true,"value":"delivered"}],"source":"scenarios/03-order-delivery.json","stableKey":"ecommerce.l3.order-delivery.order-delivery.303a","statedBy":"A shipped order becomes delivered after 60 seconds.","withheld":null},{"category":"production","checkGroupId":"order-delivery","criterionId":"305a","description":"a cancelled order remains cancelled after the delivery interval","featureId":305,"featureName":"Cancellation is final","note":null,"packId":"ecommerce.l3.order-delivery-features","points":2,"provenBy":null,"role":"feature","semantics":[{"do":"wait"},{"do":"reload"},{"do":"ensureSignedIn","name":"delivery-cancel"},{"do":"click","ifAvailable":true},{"do":"click","unlessVisible":"order-item"},{"do":"expect","ignoreCase":true,"value":"cancelled"}],"source":"scenarios/03-order-delivery.json","stableKey":"ecommerce.l3.order-delivery.order-delivery.305a","statedBy":"A cancelled order never advances.","withheld":null},{"category":"production","checkGroupId":"reservations","criterionId":"301a","description":"adding an item reserves one unit for every open viewer","featureId":301,"featureName":"A cart reserves stock","note":null,"packId":"ecommerce.l3.reservations-features","points":2,"provenBy":null,"role":"feature","semantics":[{"do":"click"},{"do":"expectNumber","plus":-1,"relativeTo":"before"}],"source":"scenarios/03-reservations.json","stableKey":"ecommerce.l3.reservations.reservations.301a","statedBy":"Adding an item to a cart reserves its stock immediately for 90 seconds.","withheld":null},{"category":"interface","checkGroupId":"reservations","criterionId":"305a","description":"the reservation timer decreases","featureId":305,"featureName":"Reservation time is visible","note":null,"packId":"ecommerce.l3.reservations-features","points":1,"provenBy":null,"role":"feature","semantics":[{"atLeast":1,"atMost":90,"do":"expectNumber"},{"as":"initial-countdown","do":"recordNumber"},{"do":"wait"},{"comparison":"atMost","do":"expectNumber","plus":-1,"relativeTo":"initial-countdown"}],"source":"scenarios/03-reservations.json","stableKey":"ecommerce.l3.reservations.reservations.305a","statedBy":"The cart shows the remaining reservation time.","withheld":null},{"category":"feature","checkGroupId":"reservations","criterionId":"306a","description":"checkout converts the reservation into an order and empties the cart","featureId":306,"featureName":"Checkout consumes a reservation","note":null,"packId":"ecommerce.l3.reservations-features","points":2,"provenBy":null,"role":"feature","semantics":[{"do":"click"},{"do":"expectNumber","equals":0},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click"},{"contains":"Keyboard","count":1,"do":"expect"}],"source":"scenarios/03-reservations.json","stableKey":"ecommerce.l3.reservations.reservations.306a","statedBy":"Checkout converts a live reservation into a sale.","withheld":null},{"category":"feature","checkGroupId":"reservations","criterionId":"307a","description":"an expired reservation marks its cart line","featureId":307,"featureName":"A reservation expires","note":null,"packId":"ecommerce.l3.reservations-features","points":3,"provenBy":null,"role":"feature","semantics":[{"do":"wait"},{"do":"expect"}],"source":"scenarios/03-reservations.json","stableKey":"ecommerce.l3.reservations.reservations.307a","statedBy":"An expired reservation remains visible as expired.","withheld":null},{"category":"feature","checkGroupId":"reservations","criterionId":"308a","description":"raising quantity starts a new reservation window","featureId":308,"featureName":"Changing quantity renews a reservation","note":null,"packId":"ecommerce.l3.reservations-features","points":2,"provenBy":null,"role":"feature","semantics":[{"do":"wait"},{"atLeast":35,"do":"expectNumber"},{"absent":true,"do":"expect"}],"source":"scenarios/03-reservations.json","stableKey":"ecommerce.l3.reservations.reservations.308a","statedBy":"Adding the item again renews the reservation.","withheld":null},{"category":"feature","checkGroupId":"scheduled-restocks","criterionId":"305a","description":"a due restock updates stock and moves to the ledger","featureId":305,"featureName":"A due restock applies","note":null,"packId":"ecommerce.l3.scheduled-restocks-features","points":3,"provenBy":null,"role":"feature","semantics":[{"as":"ledger-before","count":true,"do":"recordNumber"},{"do":"fill","text":"Keyboard"},{"do":"fill","text":"West"},{"do":"fill","text":"7"},{"do":"fill","text":"15"},{"do":"click"},{"do":"wait"},{"do":"reload"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","ifAvailable":true},{"do":"click","ifAvailable":true},{"do":"expectNumber","plus":7,"relativeTo":"before"},{"absent":true,"do":"expect"},{"do":"expectElementCount","plus":1,"relativeTo":"ledger-before"}],"source":"scenarios/03-scheduled-restock-apply.json","stableKey":"ecommerce.l3.scheduled-restocks.scheduled-restocks.305a","statedBy":"A due restock updates stock, leaves the pending list, and enters the stock ledger.","withheld":null},{"category":"production","checkGroupId":"scheduled-restocks","criterionId":"306a","description":"a cancelled restock never applies","featureId":306,"featureName":"A scheduled restock can be cancelled","note":null,"packId":"ecommerce.l3.scheduled-restocks-features","points":2,"provenBy":null,"role":"feature","semantics":[{"do":"fill","text":"Desk Lamp"},{"do":"fill","text":"East"},{"do":"fill","text":"9"},{"do":"fill","text":"15"},{"do":"click"},{"count":1,"do":"expect"},{"do":"click"},{"do":"wait"},{"do":"reload"},{"do":"expectNumber","plus":0,"relativeTo":"before"}],"source":"scenarios/03-scheduled-restock-cancel.json","stableKey":"ecommerce.l3.scheduled-restocks.scheduled-restocks.306a","statedBy":"An admin can schedule and cancel a restock.","withheld":null},{"category":"feature","checkGroupId":"scheduled-restocks","criterionId":"302a","description":"a scheduled restock is pending and its remaining time decreases","featureId":302,"featureName":"A restock is pending before it is due","note":null,"packId":"ecommerce.l3.scheduled-restocks-features","points":2,"provenBy":null,"role":"feature","semantics":[{"do":"fill","text":"Webcam"},{"do":"fill","text":"East"},{"do":"fill","text":"7"},{"do":"fill","text":"90"},{"do":"click"},{"count":1,"do":"expect"},{"atLeast":1,"atMost":90,"do":"expectNumber"},{"as":"initial-countdown","do":"recordNumber"},{"do":"wait"},{"comparison":"atMost","do":"expectNumber","plus":-1,"relativeTo":"initial-countdown"},{"do":"click"}],"source":"scenarios/03-scheduled-restocks.json","stableKey":"ecommerce.l3.scheduled-restocks.scheduled-restocks.302a","statedBy":"A pending restock shows its remaining time.","withheld":null},{"category":"production","checkGroupId":"server-time","criterionId":"312a","description":"restart preserves the due time and the work later completes","featureId":312,"featureName":"Restart does not run work early","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.l3.server-time-specifications","points":3,"provenBy":null,"requiresFeatures":["ecommerce.l3.scheduled-restocks-features"],"role":"guarantee","semantics":[{"do":"wait"},{"do":"reload"},{"atMost":100000,"do":"expectElapsed","since":"restock-start"},{"do":"dbExpectStock","item":"Espresso Machine","plus":0,"relativeTo":"before"},{"count":1,"do":"expect"},{"atMost":100000,"do":"expectElapsed","since":"restock-start"},{"do":"wait","since":"restock-start-accepted"},{"do":"dbExpectStock","item":"Espresso Machine","plus":4,"relativeTo":"before"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","ifAvailable":true},{"do":"click","ifAvailable":true},{"do":"expect"},{"absent":true,"do":"expect"}],"source":"scenarios/03-server-time.json","stableKey":"ecommerce.l3.server-time.server-time.312a","statedBy":"A pending restock does not run early after a restart.","withheld":null},{"category":"production","checkGroupId":"server-time","criterionId":"313a","description":"a reservation expires while its browser is closed","featureId":313,"featureName":"A browser is not the clock","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.l3.server-time-specifications","points":3,"provenBy":null,"requiresFeatures":["ecommerce.l3.reservations-features"],"role":"guarantee","semantics":[{"do":"wait"},{"do":"reload"},{"do":"expectNumber","plus":0,"relativeTo":"before"}],"source":"scenarios/03-server-time.json","stableKey":"ecommerce.l3.server-time.server-time.313a","statedBy":"A reservation expires without an open browser.","withheld":null},{"category":"production","checkGroupId":"account-state-recovery","criterionId":"105b","description":"the same account and cart survive the connection dropping and coming back","featureId":105,"featureName":"An account keeps what belongs to it","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.state-durability","points":1,"provenBy":null,"requiresFeatures":["ecommerce.feature.accounts","ecommerce.feature.checkout"],"role":"guarantee","semantics":[{"do":"setOffline","offline":true},{"do":"click"},{"do":"setOffline","offline":false},{"contains":"pat","do":"expect"},{"do":"click","unlessVisible":"cart-total"},{"contains":"Keyboard","do":"expect"},{"contains":"Headphones","do":"expect"}],"source":"scenarios/progression-account-state-reconnect.json","stableKey":"ecommerce.spec.state-durability.account-state-recovery.105b","statedBy":"the signed-in account and its current data remain available after reconnecting","withheld":null},{"category":"production","checkGroupId":"account-state-recovery","criterionId":"105a","description":"cart and order history survive reload and backend restart, including a fresh account login","featureId":105,"featureName":"An account keeps what belongs to it","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.state-durability","points":1,"provenBy":null,"requiresFeatures":["ecommerce.feature.accounts","ecommerce.feature.checkout"],"role":"guarantee","semantics":[{"do":"click"},{"do":"click","unlessVisible":"cart-total"},{"do":"click"},{"do":"click","ifAvailable":true},{"do":"click","ifAvailable":true},{"do":"click"},{"do":"click","unlessVisible":"cart-total"},{"contains":"Keyboard","do":"expect"},{"do":"reload"},{"contains":"pat","do":"expect"},{"do":"click","unlessVisible":"cart-total"},{"contains":"Keyboard","do":"expect"},{"do":"reload"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"contains":"Headphones","count":1,"do":"expect"},{"do":"restartBackend"},{"do":"freshClient"},{"do":"signIn","name":"pat"},{"do":"click","unlessVisible":"cart-total"},{"contains":"Keyboard","count":1,"do":"expect"},{"do":"click","ifAvailable":true},{"do":"click","unlessVisible":"order-item"},{"contains":"Headphones","count":1,"do":"expect"}],"source":"scenarios/progression-account-state-reload.json","stableKey":"ecommerce.spec.state-durability.account-state-recovery.105a","statedBy":"the signed-in account, cart, and orders persist across a page reload","withheld":null},{"category":"production","checkGroupId":"automatic-reorder-access","criterionId":"502c","description":"a customer cannot see or replay automatic reorder management","featureId":502,"featureName":"Warehouse staff manage automatic reorder rules","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"provenBy":null,"requiresFeatures":["ecommerce.progression.automatic-reorder"],"role":"guarantee","semantics":[{"absent":true,"do":"expect"},{"do":"fill","text":"Desk Lamp"},{"do":"fill","text":"1"},{"do":"fill","text":"9"},{"action":"saveReorderRule","do":"callAction","from":"staff","input":{"attribute":"data-action-input","testid":"reorder-submit"},"namedAction":{"args":[0,1,9],"id":"saveReorderRule","method":"PUT","params":[{"in":"path","name":"itemId","placeholder":"{itemId}","wireType":"u64"},{"in":"body","name":"threshold"},{"in":"body","name":"quantity"}],"path":"/api/reorders/{itemId}","reducer":"save_reorder_rule"}},{"do":"expectActionOutcome","outcome":"refused","routeProvenBy":"staff"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"do":"click","ifAvailable":true},{"do":"click","unlessVisible":"reorder-submit"},{"attribute":"data-threshold","contains":"Desk Lamp","count":1,"do":"expect","value":"2"},{"attribute":"data-quantity","contains":"Desk Lamp","do":"expect","value":"5"}],"source":"scenarios/progression-automatic-reorder-access.json","stableKey":"ecommerce.spec.access-control.automatic-reorder-access.502c","statedBy":"Only warehouse staff can manage automatic reorder rules.","withheld":null},{"category":"production","checkGroupId":"automatic-reorder-deduplication","criterionId":"502b","description":"more sales do not duplicate a pending restock","featureId":502,"featureName":"Warehouse staff manage automatic reorder rules","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.transactional-integrity","points":2,"provenBy":null,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.progression.automatic-reorder"],"role":"guarantee","semantics":[{"action":"buy","do":"callAction","input":{"attribute":"data-buy-input","contains":"Desk Lamp","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"}},{"do":"expectActionOutcome","outcome":"accepted"},{"action":"buy","do":"callAction","input":{"attribute":"data-buy-input","contains":"Desk Lamp","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"}},{"do":"expectActionOutcome","outcome":"accepted"},{"do":"dbExpectStock","equals":0,"item":"Desk Lamp"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","ifAvailable":true},{"do":"click","unlessVisible":"admin-revenue"},{"do":"click","ifAvailable":true},{"do":"expect"},{"do":"expectElementCount","equals":1},{"attribute":"data-quantity","contains":"Desk Lamp","count":1,"do":"expect","value":"5"}],"source":"scenarios/progression-automatic-reorder-duplicate.json","stableKey":"ecommerce.spec.transactional-integrity.automatic-reorder-deduplication.502b","statedBy":"A pending automatic restock is not scheduled twice.","withheld":null},{"category":"feature","checkGroupId":"automatic-reorder","criterionId":"502a","description":"crossing the threshold creates one pending restock","featureId":502,"featureName":"Warehouse staff manage automatic reorder rules","note":null,"packId":"ecommerce.progression.automatic-reorder","points":3,"provenBy":null,"requiresFeatures":["ecommerce.feature.purchasing"],"role":"feature","semantics":[{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","ifAvailable":true},{"do":"click","unlessVisible":"admin-revenue"},{"do":"click","ifAvailable":true},{"do":"expect"},{"do":"expectElementCount","equals":0},{"action":"buy","do":"callAction","input":{"attribute":"data-buy-input","contains":"Desk Lamp","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"}},{"do":"expectActionOutcome","outcome":"accepted"},{"do":"dbExpectStock","equals":2,"item":"Desk Lamp"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","ifAvailable":true},{"do":"click","unlessVisible":"admin-revenue"},{"do":"click","ifAvailable":true},{"do":"expect"},{"do":"expectElementCount","equals":1},{"attribute":"data-quantity","contains":"Desk Lamp","count":1,"do":"expect","value":"5"}],"source":"scenarios/progression-automatic-reorder.json","stableKey":"ecommerce.progression.automatic-reorder.automatic-reorder.502a","statedBy":"Crossing a reorder threshold schedules a restock.","withheld":null},{"category":"production","checkGroupId":"books-balance","criterionId":"107a","description":"revenue rises by exactly what was bought","featureId":107,"featureName":"The books balance","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.transactional-integrity","points":1,"provenBy":null,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.warehouse-admin"],"role":"guarantee","semantics":[{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","ifAvailable":true},{"do":"click","unlessVisible":"admin-revenue"},{"do":"expectNumber","plus":58,"relativeTo":"revenue-before"}],"source":"scenarios/progression-books-balance.json","stableKey":"ecommerce.spec.transactional-integrity.books-balance.107a","statedBy":"total revenue equals the sum of order totals","withheld":null},{"category":"production","checkGroupId":"books-balance","criterionId":"107b","description":"what the store sold is what left the warehouses, and a fresh client agrees","featureId":107,"featureName":"The books balance","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.transactional-integrity","points":1,"provenBy":null,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.warehouse-admin"],"role":"guarantee","semantics":[{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","ifAvailable":true},{"do":"expectNumber","plus":-2,"relativeTo":"stand-before"},{"do":"freshClient"},{"do":"expectNumber","plus":-2,"relativeTo":"stand-before"}],"source":"scenarios/progression-books-balance.json","stableKey":"ecommerce.spec.transactional-integrity.books-balance.107b","statedBy":"warehouse totals and a fresh storefront agree with completed sales","withheld":null},{"category":"feature","checkGroupId":"bundle-checkout","criterionId":"741a","description":"adding a bundle reserves its components and checkout records the bundle price once","featureId":741,"featureName":"Bundle checkout","note":null,"packId":"ecommerce.feature.bundle-checkout","points":2,"provenBy":null,"role":"feature","semantics":[{"do":"click"},{"do":"dbExpectStock","equals":4,"item":"Keyboard","warehouse":"East"},{"do":"dbExpectStock","equals":3,"item":"Desk Lamp","warehouse":"East"},{"do":"click"},{"do":"click"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click"},{"contains":"Checkout bundle","count":1,"do":"expect"},{"do":"expectNumber","equals":75},{"do":"dbExpectStock","equals":4,"item":"Keyboard","warehouse":"East"},{"do":"dbExpectStock","equals":3,"item":"Desk Lamp","warehouse":"East"},{"do":"dbExpectStock","equals":0,"item":"Keyboard","warehouse":"West"},{"do":"dbExpectStock","equals":0,"item":"Desk Lamp","warehouse":"West"}],"source":"scenarios/progression-bundle-checkout.json","stableKey":"ecommerce.feature.bundle-checkout.bundle-checkout.741a","statedBy":null,"withheld":null},{"category":"production","checkGroupId":"bundle-744","criterionId":"744a","description":"two competing reservations accept exactly one whole bundle without consuming extra components","featureId":744,"featureName":"Competing bundle reservations","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.bundle-integrity","points":3,"provenBy":null,"requiresFeatures":["ecommerce.feature.bundle-checkout"],"role":"guarantee","semantics":[{"action":"addBundleToCart","do":"callConcurrently","input":{"attribute":"data-bundle-input","contains":"Scarce bundle","testid":"bundle-card"},"namedAction":{"args":[0],"id":"addBundleToCart","params":[{"in":"body","name":"bundleId","wireType":"u64"}],"path":"/api/cart/bundles","reducer":"add_bundle_to_cart"}},{"accepted":1,"do":"expectCallOutcomes"},{"do":"dbExpectStock","equals":0,"item":"Keyboard","warehouse":"East"},{"do":"dbExpectStock","equals":0,"item":"Desk Lamp","warehouse":"East"},{"do":"reload"},{"do":"reload"},{"do":"click"},{"do":"click"},{"contains":"Scarce bundle","do":"expectActorsWith","equals":1,"maxEach":1},{"do":"click","ifAvailable":true},{"do":"click","ifAvailable":true},{"do":"dbExpectStock","equals":2,"item":"Keyboard","warehouse":"East"},{"do":"dbExpectStock","equals":1,"item":"Desk Lamp","warehouse":"East"}],"source":"scenarios/progression-bundle-checkout.json","stableKey":"ecommerce.spec.bundle-integrity.bundle-744.744a","statedBy":null,"withheld":null},{"category":"production","checkGroupId":"bundle-745","criterionId":"745a","description":"a missing component refuses the reservation without taking available stock or adding a cart line","featureId":745,"featureName":"Incomplete bundle stock","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.bundle-integrity","points":3,"provenBy":null,"requiresFeatures":["ecommerce.feature.bundle-checkout"],"role":"guarantee","semantics":[{"action":"addBundleToCart","do":"callAction","input":{"attribute":"data-bundle-input","contains":"Unavailable bundle","testid":"bundle-card"},"namedAction":{"args":[0],"id":"addBundleToCart","params":[{"in":"body","name":"bundleId","wireType":"u64"}],"path":"/api/cart/bundles","reducer":"add_bundle_to_cart"}},{"do":"expectActionOutcome","outcome":"application-refused"},{"do":"dbExpectStock","equals":2,"item":"Keyboard","warehouse":"East"},{"do":"dbExpectStock","equals":0,"item":"Desk Lamp","warehouse":"East"},{"do":"click"},{"absent":true,"contains":"Unavailable bundle","do":"expect"}],"source":"scenarios/progression-bundle-checkout.json","stableKey":"ecommerce.spec.bundle-integrity.bundle-745.745a","statedBy":null,"withheld":null},{"category":"production","checkGroupId":"bundle-746","criterionId":"746a","description":"an expired reservation releases each component once across a backend restart","featureId":746,"featureName":"Bundle reservation restart","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.bundle-integrity","points":3,"provenBy":null,"requiresFeatures":["ecommerce.feature.bundle-checkout"],"role":"guarantee","semantics":[{"do":"click"},{"do":"dbExpectStock","equals":4,"item":"Keyboard","warehouse":"East"},{"do":"dbExpectStock","equals":3,"item":"Desk Lamp","warehouse":"East"},{"do":"restartBackend"},{"do":"wait"},{"do":"reload"},{"do":"ensureSignedIn","name":"bundle-expiry"},{"do":"click"},{"do":"expect"},{"do":"dbExpectStock","equals":6,"item":"Keyboard","warehouse":"East"},{"do":"dbExpectStock","equals":4,"item":"Desk Lamp","warehouse":"East"},{"do":"restartBackend"},{"do":"dbExpectStock","equals":6,"item":"Keyboard","warehouse":"East"},{"do":"dbExpectStock","equals":4,"item":"Desk Lamp","warehouse":"East"}],"source":"scenarios/progression-bundle-checkout.json","stableKey":"ecommerce.spec.bundle-integrity.bundle-746.746a","statedBy":null,"withheld":null},{"category":"production","checkGroupId":"bundle-747","criterionId":"747a","description":"two checkout requests consume one reservation and create one paid bundle","featureId":747,"featureName":"Repeated bundle checkout","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.bundle-integrity","points":3,"provenBy":null,"requiresFeatures":["ecommerce.feature.bundle-checkout"],"role":"guarantee","semantics":[{"action":"checkout","do":"callConcurrently"},{"accepted":1,"do":"expectCallOutcomes"},{"do":"reload"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click"},{"contains":"Repeated bundle","count":1,"do":"expect"},{"do":"expectNumber","equals":75},{"do":"dbExpectStock","equals":4,"item":"Keyboard","warehouse":"East"},{"do":"dbExpectStock","equals":3,"item":"Desk Lamp","warehouse":"East"}],"source":"scenarios/progression-bundle-checkout.json","stableKey":"ecommerce.spec.bundle-integrity.bundle-747.747a","statedBy":null,"withheld":null},{"category":"feature","checkGroupId":"bundle-returns","criterionId":"742a","description":"returning a shipped bundle refunds the paid price and restores original components after its definition changes","featureId":742,"featureName":"Historical bundle return","note":null,"packId":"ecommerce.feature.bundle-returns","points":2,"provenBy":null,"role":"feature","semantics":[{"do":"fill","text":"Historical bundle"},{"do":"fill","text":"9.00"},{"do":"fill","text":"[{\"item\":\"Keyboard\",\"quantity\":1},{\"item\":\"Desk Lamp\",\"quantity\":3}]"},{"do":"click"},{"contains":"Historical bundle","do":"expect"},{"do":"click"},{"do":"expect","ignoreCase":true,"value":"returned"},{"do":"expectNumber","equals":75},{"do":"dbExpectStock","equals":6,"item":"Keyboard","warehouse":"East"},{"do":"dbExpectStock","equals":4,"item":"Desk Lamp","warehouse":"East"},{"do":"dbExpectStock","equals":0,"item":"Keyboard","warehouse":"West"},{"do":"dbExpectStock","equals":0,"item":"Desk Lamp","warehouse":"West"}],"source":"scenarios/progression-bundle-returns.json","stableKey":"ecommerce.feature.bundle-returns.bundle-returns.742a","statedBy":null,"withheld":null},{"category":"production","checkGroupId":"bundle-742","criterionId":"742b","description":"replaying a completed bundle return after restart does not refund or restock it twice","featureId":742,"featureName":"Historical bundle return","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.bundle-integrity","points":3,"provenBy":null,"requiresFeatures":["ecommerce.feature.bundle-returns"],"role":"guarantee","semantics":[{"do":"restartBackend"},{"do":"reload"},{"do":"ensureSignedIn","name":"Historical bundle"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click"},{"action":"returnBundle","do":"callAction","input":{"attribute":"data-bundle-return-input","contains":"Historical bundle","testid":"order-item"},"namedAction":{"args":[0],"id":"returnBundle","params":[{"in":"path","name":"orderId","placeholder":":orderId","wireType":"u64"}],"path":"/api/bundle-orders/:orderId/return","reducer":"return_bundle"}},{"do":"reload"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click"},{"do":"expectNumber","equals":75},{"do":"dbExpectStock","equals":6,"item":"Keyboard","warehouse":"East"},{"do":"dbExpectStock","equals":4,"item":"Desk Lamp","warehouse":"East"}],"source":"scenarios/progression-bundle-returns.json","stableKey":"ecommerce.spec.bundle-integrity.bundle-742.742b","statedBy":null,"withheld":null},{"category":"production","checkGroupId":"bundle-748","criterionId":"748a","description":"another customer cannot return a paid bundle by submitting its order ID","featureId":748,"featureName":"Bundle return ownership","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.bundle-integrity","points":3,"provenBy":null,"requiresFeatures":["ecommerce.feature.bundle-returns"],"role":"guarantee","semantics":[{"action":"returnBundle","do":"callAction","from":"buyer","input":{"attribute":"data-bundle-return-input","contains":"Private bundle","testid":"order-item"},"namedAction":{"args":[0],"id":"returnBundle","params":[{"in":"path","name":"orderId","placeholder":":orderId","wireType":"u64"}],"path":"/api/bundle-orders/:orderId/return","reducer":"return_bundle"}},{"do":"expectActionOutcome","outcome":"application-refused"},{"do":"reload"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click"},{"do":"expect","ignoreCase":true,"value":"shipped"},{"do":"dbExpectStock","equals":4,"item":"Keyboard","warehouse":"East"},{"do":"dbExpectStock","equals":3,"item":"Desk Lamp","warehouse":"East"},{"do":"click"},{"do":"expectNumber","equals":75},{"do":"dbExpectStock","equals":6,"item":"Keyboard","warehouse":"East"},{"do":"dbExpectStock","equals":4,"item":"Desk Lamp","warehouse":"East"}],"source":"scenarios/progression-bundle-returns.json","stableKey":"ecommerce.spec.bundle-integrity.bundle-748.748a","statedBy":null,"withheld":null},{"category":"feature","checkGroupId":"cart","criterionId":"4a","description":"adding the same item twice raises its quantity instead of adding a second line","featureId":4,"featureName":"Account cart and checkout","note":null,"packId":"ecommerce.feature.cart","points":1,"provenBy":null,"role":"feature","semantics":[{"do":"click"},{"do":"wait"},{"do":"click","ifAvailable":true},{"do":"click","ifAvailable":true},{"do":"click"},{"do":"click","unlessVisible":"cart-total"},{"contains":"Headphones","count":1,"do":"expect"},{"do":"expectNumber","equals":2}],"source":"scenarios/progression-cart-checkout.json","stableKey":"ecommerce.feature.cart-checkout.cart.4a","statedBy":"Adding an existing cart item increases its quantity.","withheld":null},{"category":"feature","checkGroupId":"cart","criterionId":"4d","description":"checkout creates one order, reduces stock, and empties the cart","featureId":4,"featureName":"Account cart and checkout","note":null,"packId":"ecommerce.feature.checkout","points":2,"provenBy":null,"role":"feature","semantics":[{"do":"expectNumber","equals":100},{"do":"click"},{"do":"click","unlessVisible":"cart-total"},{"do":"expectNumber","equals":1},{"do":"click"},{"do":"wait"},{"do":"reload"},{"do":"ensureSignedIn","name":"cart-checkout"},{"do":"click","unlessVisible":"cart-total"},{"do":"expectNumber","equals":0},{"do":"click","ifAvailable":true},{"do":"click","ifAvailable":true},{"do":"expectNumber","equals":99},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"contains":"Desk Lamp","count":1,"do":"expect"}],"source":"scenarios/progression-cart-checkout.json","stableKey":"ecommerce.feature.cart-checkout.cart.4d","statedBy":"Checkout creates one order, reduces stock, and empties the cart.","withheld":null},{"category":"feature","checkGroupId":"cart-recovery","criterionId":"503a","description":"restoring an expired cart reserves available items again","featureId":503,"featureName":"Expired carts restore only available items","note":null,"packId":"ecommerce.progression.cart-recovery","points":3,"provenBy":null,"role":"feature","semantics":[{"do":"reload"},{"do":"ensureSignedIn","name":"cart-recovery-available"},{"do":"expect"},{"do":"expectNumber","equals":0},{"as":"restore-available-shopper","do":"recordNumber"},{"do":"click"},{"do":"click"},{"contains":"Keyboard","do":"expect"},{"absent":true,"do":"expect"},{"do":"expectNumber","equals":1},{"do":"reload"},{"do":"ensureSignedIn","name":"cart-recovery-available"},{"do":"click","ifAvailable":true},{"do":"click","unlessVisible":"item-card"},{"do":"expectNumber","plus":-1,"relativeTo":"restore-available-shopper"}],"source":"scenarios/progression-cart-recovery.json","stableKey":"ecommerce.progression.cart-recovery.cart-recovery.503a","statedBy":"A customer can restore the available items from an expired cart.","withheld":null},{"category":"feature","checkGroupId":"cart-recovery","criterionId":"503b","description":"a partial restore keeps available items and names each unavailable item","featureId":503,"featureName":"Expired carts restore only available items","note":null,"packId":"ecommerce.progression.cart-recovery","points":3,"provenBy":null,"role":"feature","semantics":[{"do":"reload"},{"do":"ensureSignedIn","name":"cart-recovery-partial"},{"do":"expect"},{"do":"expectNumber","equals":0},{"as":"restore-partial-shopper","do":"recordNumber"},{"do":"dbSetStock","item":"Desk Lamp","quantity":0,"warehouse":"East"},{"do":"dbSetStock","item":"Desk Lamp","quantity":0,"warehouse":"West"},{"do":"click"},{"do":"click"},{"contains":"Gaming Mouse","do":"expect"},{"absent":true,"contains":"Desk Lamp","do":"expect"},{"contains":"Desk Lamp","do":"expect"},{"do":"expectNumber","equals":1},{"do":"reload"},{"do":"ensureSignedIn","name":"cart-recovery-partial"},{"do":"click","ifAvailable":true},{"do":"click","unlessVisible":"item-card"},{"do":"expectNumber","plus":-1,"relativeTo":"restore-partial-shopper"}],"source":"scenarios/progression-cart-recovery.json","stableKey":"ecommerce.progression.cart-recovery.cart-recovery.503b","statedBy":"Restore the available items and list each item that could not be restored.","withheld":null},{"category":"feature","checkGroupId":"catalog-management","criterionId":"622a","description":"a new product reaches the public catalog","featureId":622,"featureName":"Catalog management","note":null,"packId":"ecommerce.progression.catalog-management","points":2,"provenBy":null,"role":"feature","semantics":[{"contains":"Travel Mug","do":"expect"}],"source":"scenarios/progression-catalog-management.json","stableKey":"ecommerce.progression.catalog-management.catalog-management.622a","statedBy":"Authorized staff can add products.","withheld":null},{"category":"feature","checkGroupId":"catalog-management","criterionId":"622b","description":"the product exposes its named variants","featureId":622,"featureName":"Catalog management","note":null,"packId":"ecommerce.progression.catalog-management","points":2,"provenBy":null,"role":"feature","semantics":[{"do":"openItem","item":"Travel Mug","unlessVisible":"item-variant"},{"contains":"Black","do":"expectElementCount","equals":1},{"contains":"Silver","do":"expectElementCount","equals":1}],"source":"scenarios/progression-catalog-management.json","stableKey":"ecommerce.progression.catalog-management.catalog-management.622b","statedBy":"Products can have named variants.","withheld":null},{"category":"production","checkGroupId":"checkout-crash-integrity","criterionId":"910a","description":"interrupted checkout recovers to the prepared cart or one complete order with the cart cleared after each independent process crash","featureId":910,"featureName":"Checkout crash recovery","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.state-durability","points":1,"provenBy":null,"requiresFeatures":["ecommerce.feature.checkout"],"role":"guarantee","semantics":[{"do":"expectCrashCheckout","from":"database-crash-observation","verdict":"atomicity"},{"do":"expectCrashCheckout","from":"application-crash-observation","verdict":"atomicity"}],"source":"scenarios/progression-checkout-crash.json","stableKey":"ecommerce.spec.state-durability.checkout-crash-integrity.910a","statedBy":null,"withheld":null},{"category":"production","checkGroupId":"checkout-crash-durability","criterionId":"910b","description":"acknowledged checkout is not rolled back and earlier orders remain unchanged after each independent process crash","featureId":910,"featureName":"Checkout crash recovery","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.state-durability","points":1,"provenBy":null,"requiresFeatures":["ecommerce.feature.checkout"],"role":"guarantee","semantics":[{"do":"expectCrashCheckout","from":"database-crash-observation","verdict":"durability"},{"do":"expectCrashCheckout","from":"application-crash-observation","verdict":"durability"}],"source":"scenarios/progression-checkout-crash.json","stableKey":"ecommerce.spec.state-durability.checkout-crash-durability.910b","statedBy":null,"withheld":null},{"category":"production","checkGroupId":"payment-records","criterionId":"623a","description":"checkout records the exact paid amount","featureId":623,"featureName":"Payment records","note":null,"packId":"ecommerce.progression.payment-records","points":3,"provenBy":null,"role":"feature","semantics":[{"do":"expect","ignoreCase":true,"value":"paid"},{"do":"expectNumber","plus":0,"relativeTo":"payment-total"}],"source":"scenarios/progression-core-business.json","stableKey":"ecommerce.progression.payment-records.payment-records.623a","statedBy":"Checkout records the amount paid on the order.","withheld":null},{"category":"production","checkGroupId":"payment-deduplication","criterionId":"623b","description":"one checkout has one payment record","featureId":623,"featureName":"Payment records","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.transactional-integrity","points":2,"provenBy":null,"requiresFeatures":["ecommerce.progression.payment-records"],"role":"guarantee","semantics":[{"do":"expectElementCount","equals":1}],"source":"scenarios/progression-core-business.json","stableKey":"ecommerce.spec.transactional-integrity.payment-deduplication.623b","statedBy":"A checkout does not create duplicate payments.","withheld":null},{"category":"feature","checkGroupId":"customer-profile","criterionId":"620c","description":"the owner can save and view a customer profile","featureId":620,"featureName":"Customer profile","note":null,"packId":"ecommerce.progression.customer-profile","points":1,"provenBy":null,"role":"feature","semantics":[{"do":"click","ifAvailable":true},{"do":"click","ifAvailable":true},{"do":"click","unlessVisible":"profile-address-summary"},{"contains":"14 Market Street {user:profilemarker}","do":"expect"}],"source":"scenarios/progression-customer-profile.json","stableKey":"ecommerce.progression.customer-profile.customer-profile.620c","statedBy":"A signed-in customer can save and view their name and shipping address.","withheld":null},{"category":"production","checkGroupId":"customer-profile-reload","criterionId":"620a","description":"the saved profile survives reload and backend restart in a fresh browser","featureId":620,"featureName":"Customer profile","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.state-durability","points":2,"provenBy":null,"requiresFeatures":["ecommerce.progression.customer-profile"],"role":"guarantee","semantics":[{"do":"reload"},{"do":"ensureSignedIn","name":"profile-owner"},{"do":"click"},{"contains":"14 Market Street {user:profilemarker}","do":"expect"},{"do":"restartBackend"},{"do":"freshClient"},{"do":"signIn","name":"profile-owner"},{"do":"click"},{"contains":"14 Market Street {user:profilemarker}","do":"expect"}],"source":"scenarios/progression-customer-profile.json","stableKey":"ecommerce.spec.state-durability.customer-profile-reload.620a","statedBy":"The saved profile remains after a reload.","withheld":null},{"category":"production","checkGroupId":"customer-profile-privacy","criterionId":"620b","description":"another customer neither sees nor receives the owner's private address","featureId":620,"featureName":"Customer profile","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"provenBy":null,"requiresFeatures":["ecommerce.progression.customer-profile"],"role":"guarantee","semantics":[{"do":"reload"},{"do":"signUp","name":"profile-private-owner"},{"do":"click"},{"do":"fill","text":"Avery Stone"},{"do":"fill","text":"14 Market Street {user:profilemarker}"},{"do":"click"},{"do":"reload"},{"do":"ensureSignedIn","name":"profile-private-owner"},{"do":"click"},{"contains":"14 Market Street {user:profilemarker}","do":"expect"},{"contains":"14 Market Street {user:profilemarker}","do":"expectReceived"},{"do":"reload"},{"do":"signUp","name":"profile-other"},{"do":"click"},{"absent":true,"contains":"14 Market Street {user:profilemarker}","do":"expect"},{"contains":"14 Market Street {user:profilemarker}","do":"expectNotReceived"}],"source":"scenarios/progression-customer-profile.json","stableKey":"ecommerce.spec.access-control.customer-profile-privacy.620b","statedBy":"Each customer can see only their own profile.","withheld":null},{"category":"feature","checkGroupId":"delivery-notification-delivery","criterionId":"501a","description":"the order owner receives one delivery notification","featureId":501,"featureName":"Delivery creates one private notification","note":null,"packId":"ecommerce.progression.delivery-notifications","points":3,"provenBy":null,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.progression.fulfilment-queue"],"role":"feature","semantics":[{"do":"reload"},{"do":"ensureSignedIn","name":"delivery-owner"},{"do":"click","unlessVisible":"notifications-panel"},{"attribute":"aria-busy","do":"expect","value":"false"},{"contains":"Desk Lamp","do":"expectElementCount","equals":1}],"source":"scenarios/progression-delivery-notifications.json","stableKey":"ecommerce.progression.delivery-notifications.delivery-notification-delivery.501a","statedBy":"A delivered order creates one notification for its owner.","withheld":null},{"category":"production","checkGroupId":"delivery-notification-privacy","criterionId":"501b","description":"another customer cannot see the delivery notification","featureId":501,"featureName":"Delivery creates one private notification","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"provenBy":null,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.progression.delivery-notifications","ecommerce.progression.fulfilment-queue"],"role":"guarantee","semantics":[{"do":"reload"},{"do":"ensureSignedIn","name":"delivery-owner"},{"do":"click","unlessVisible":"notifications-panel"},{"contains":"Desk Lamp","do":"expectElementCount","equals":1},{"do":"click","unlessVisible":"notifications-panel"},{"attribute":"aria-busy","do":"expect","value":"false"},{"absent":true,"contains":"Desk Lamp","do":"expect"}],"source":"scenarios/progression-delivery-notifications.json","stableKey":"ecommerce.spec.access-control.delivery-notification-privacy.501b","statedBy":"Delivery notifications are private to the order owner.","withheld":null},{"category":"feature","checkGroupId":"faceted-search","criterionId":"401a","description":"category, price, and availability filters apply together","featureId":401,"featureName":"Filters compose","note":null,"packId":"ecommerce.progression.faceted-search","points":3,"provenBy":null,"role":"feature","semantics":[{"contains":"Coffee Grinder","do":"expectElementCount","equals":1},{"do":"click"},{"do":"click","ifAvailable":true},{"do":"waitUntilAbsent"},{"contains":"Air Purifier","do":"expectElementCount","equals":1},{"absent":true,"contains":"USB Cable","do":"expect"},{"absent":true,"contains":"Desk Lamp","do":"expect"},{"absent":true,"contains":"Espresso Machine","do":"expect"},{"absent":true,"contains":"Gaming Mouse","do":"expect"}],"source":"scenarios/progression-faceted-filters.json","stableKey":"ecommerce.progression.faceted-search.faceted-search.401a","statedBy":"Apply all selected filters together","withheld":null},{"category":"feature","checkGroupId":"faceted-search","criterionId":"402a","description":"moving between pages returns the same ordered items without duplicates","featureId":402,"featureName":"Pages are stable","note":null,"packId":"ecommerce.progression.faceted-search","points":3,"provenBy":null,"role":"feature","semantics":[{"do":"expectSequence","equals":["Air Purifier","Bluetooth Speaker","Coffee Grinder","Desk Lamp","Espresso Machine","Gaming Mouse","Headphones","Induction Cooktop","Keyboard","Laptop Stand"]},{"do":"click"},{"do":"expectSequence","equals":["Mirrorless Camera","USB Cable","Webcam"]},{"do":"click"},{"do":"expectSequence","equals":["Air Purifier","Bluetooth Speaker","Coffee Grinder","Desk Lamp","Espresso Machine","Gaming Mouse","Headphones","Induction Cooktop","Keyboard","Laptop Stand"]}],"source":"scenarios/progression-faceted-pagination.json","stableKey":"ecommerce.progression.faceted-search.faceted-search.402a","statedBy":"Moving between pages must not omit or repeat an item","withheld":null},{"category":"production","checkGroupId":"managed-support-privacy","criterionId":"613b","description":"another customer cannot read or reply to the managed case","featureId":613,"featureName":"Managed support privacy","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":1,"provenBy":null,"requiresFeatures":["ecommerce.progression.managed-support"],"role":"guarantee","semantics":[{"do":"reload"},{"do":"ensureSignedIn","name":"managed-private-owner"},{"do":"click"},{"contains":"Private managed case {user:casemarker}","do":"expect"},{"contains":"Private managed case {user:casemarker}","do":"expectReceived"},{"absent":true,"contains":"Private managed case {user:casemarker}","do":"expect"},{"contains":"Private managed case {user:casemarker}","do":"expectNotReceived"},{"do":"fill","text":"Owner-only update"},{"do":"click"},{"do":"replayAs","from":"owner","match":"Owner-only update","namedAction":{"args":[0,"Owner-only update"],"id":"replySupport","method":"POST","params":[{"in":"path","name":"ticketId","placeholder":":id","wireType":"u64"},{"in":"body","name":"body"}],"path":"/api/support/:id/replies","reducer":"reply_support"},"namedTarget":{"attribute":"data-entity-id","contains":"Private managed case {user:casemarker}","testid":"support-ticket","valueType":"string"}},{"allowNotFound":true,"do":"expectReplayRejected"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"do":"click","ifAvailable":true,"unlessVisible":"support-assignee"},{"do":"click","ifAvailable":true,"unlessVisible":"support-assignee"},{"contains":"Private managed case {user:casemarker}","do":"expect"},{"contains":"Owner-only update","do":"expectElementCount","equals":1},{"contains":"Owner-only update","do":"expectReceived"},{"contains":"Owner-only update","do":"expectNotReceived"}],"source":"scenarios/progression-managed-support-privacy.json","stableKey":"ecommerce.spec.access-control.managed-support-privacy.613b","statedBy":"A customer can access only cases that belong to their account.","withheld":null},{"category":"feature","checkGroupId":"managed-support","criterionId":"613c","description":"staff can update a support case and the customer can reply","featureId":613,"featureName":"Shared managed support case","note":null,"packId":"ecommerce.progression.managed-support","points":1,"provenBy":null,"role":"feature","semantics":[{"do":"fill","text":"in progress"},{"do":"click"},{"do":"fill","text":"Case received."},{"do":"click"},{"do":"reload"},{"do":"ensureSignedIn","name":"managed-shared-owner"},{"do":"click"},{"contains":"in progress","do":"expect"},{"contains":"Case received.","do":"expect"},{"do":"fill","text":"Thank you."},{"do":"click"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"do":"click","unlessVisible":"support-assignee"},{"do":"click","ifAvailable":true,"unlessVisible":"support-assignee"},{"contains":"Thank you.","do":"expect"}],"source":"scenarios/progression-managed-support-shared.json","stableKey":"ecommerce.progression.managed-support.managed-support.613c","statedBy":"Customers and staff can exchange replies and update the status of a support case.","withheld":null},{"category":"production","checkGroupId":"managed-support","criterionId":"613a","description":"the customer and staff see the same replies and status live","featureId":613,"featureName":"Shared managed support case","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.live-state","points":2,"provenBy":null,"requiresFeatures":["ecommerce.progression.managed-support"],"role":"guarantee","semantics":[{"do":"fill","text":"open"},{"do":"click"},{"contains":"open","do":"expect"},{"do":"reload"},{"do":"ensureSignedIn","name":"managed-shared-owner"},{"do":"click","unlessVisible":"support-ticket"},{"contains":"open","do":"expect"},{"do":"fill","text":"in progress"},{"do":"click"},{"do":"fill","text":"We are investigating."},{"do":"click"},{"contains":"in progress","do":"expect"},{"contains":"We are investigating.","do":"expect"},{"do":"fill","text":"Thank you for the update."},{"do":"click"},{"contains":"Thank you for the update.","do":"expect"}],"source":"scenarios/progression-managed-support-shared.json","stableKey":"ecommerce.spec.live-state.managed-support.613a","statedBy":"Customers and authorized staff use one shared support case.","withheld":null},{"category":"feature","checkGroupId":"notification-preferences","criterionId":"630c","description":"the customer can save a notification choice","featureId":630,"featureName":"Account notification preferences","note":null,"packId":"ecommerce.progression.notification-preferences","points":1,"provenBy":null,"role":"feature","semantics":[{"do":"click","ifAvailable":true},{"do":"click","ifAvailable":true},{"do":"click","unlessVisible":"notification-order"},{"attribute":"data-state","do":"expect","value":"on"}],"source":"scenarios/progression-notification-preferences.json","stableKey":"ecommerce.progression.notification-preferences.notification-preferences.630c","statedBy":"Signed-in customers can turn order and stock notifications on or off.","withheld":null},{"category":"production","checkGroupId":"notification-preferences-reload","criterionId":"630a","description":"notification choices survive reload and backend restart in a fresh browser","featureId":630,"featureName":"Account notification preferences","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.state-durability","points":2,"provenBy":null,"requiresFeatures":["ecommerce.progression.notification-preferences"],"role":"guarantee","semantics":[{"do":"reload"},{"do":"ensureSignedIn","name":"notification-owner"},{"do":"click","unlessVisible":"notification-order"},{"attribute":"data-state","do":"expect","value":"on"},{"do":"restartBackend"},{"do":"freshClient"},{"do":"signIn","name":"notification-owner"},{"do":"click","unlessVisible":"notification-order"},{"attribute":"data-state","do":"expect","value":"on"}],"source":"scenarios/progression-notification-preferences.json","stableKey":"ecommerce.spec.state-durability.notification-preferences-reload.630a","statedBy":"Notification choices persist for the account.","withheld":null},{"category":"production","checkGroupId":"notification-preferences-privacy","criterionId":"630b","description":"the owner's choice does not change another account","featureId":630,"featureName":"Account notification preferences","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"provenBy":null,"requiresFeatures":["ecommerce.progression.notification-preferences"],"role":"guarantee","semantics":[{"do":"click","unlessVisible":"notification-order"},{"attribute":"data-state","do":"expect","value":"off"}],"source":"scenarios/progression-notification-preferences.json","stableKey":"ecommerce.spec.access-control.notification-preferences-privacy.630b","statedBy":"One customer's notification choices do not affect another customer.","withheld":null},{"category":"production","checkGroupId":"open-list","criterionId":"902a","description":"one customer has the Keyboard's reviews open before another posts one; the already-open view shows that review exactly once","featureId":902,"featureName":"An open list stays current","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.live-state","points":1,"provenBy":null,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.reviews"],"role":"guarantee","semantics":[{"do":"openItem","item":"Keyboard"},{"do":"expect"},{"do":"click","ifAvailable":true,"unlessVisible":"review-rating"},{"do":"fill","text":"live-review-kbd"},{"do":"click"},{"contains":"live-review-kbd","do":"expectElementCount","equals":1},{"contains":"live-review-kbd","do":"expectElementCount","equals":1}],"source":"scenarios/progression-open-list-live.json","stableKey":"ecommerce.spec.live-state.open-list.902a","statedBy":"A view opened while a review is submitted converges to the current review list.","withheld":null},{"category":"interface","checkGroupId":"cancellation-and-return","criterionId":"3e","description":"a pending order does not offer a return button","featureId":331,"featureName":"Pending order return boundary","note":null,"packId":"ecommerce.l3.order-returns-features","points":1,"provenBy":null,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.progression.fulfilment-queue"],"role":"feature","semantics":[{"absent":true,"do":"expect"}],"source":"scenarios/progression-order-return-boundary.json","stableKey":"ecommerce.returns-pricing.cancellation-and-return.3e","statedBy":"An item from a pending order cannot be returned.","withheld":null},{"category":"production","checkGroupId":"cancellation-and-return","criterionId":"3f","description":"the server refuses a pending return without changing stock or revenue","featureId":332,"featureName":"Pending return server boundary","note":null,"packId":"ecommerce.l3.order-returns-features","points":2,"provenBy":null,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.progression.fulfilment-queue"],"role":"feature","semantics":[{"action":"returnItem","do":"callAction","input":{"attribute":"data-return-input","contains":"Desk Lamp","testid":"order-line"},"namedAction":{"args":[0,0],"id":"returnItem","method":"POST","params":[{"in":"path","name":"orderId","placeholder":"{orderId}","wireType":"u64"},{"in":"path","name":"itemId","placeholder":"{itemId}","wireType":"u64"}],"path":"/api/orders/{orderId}/items/{itemId}/return","reducer":"return_order_item"}},{"do":"expectActionOutcome","outcome":"validation-refused"},{"do":"reload"},{"do":"ensureSignedIn","name":"return-boundary"},{"do":"click","ifAvailable":true},{"do":"click","unlessVisible":"order-item"},{"do":"expect","ignoreCase":true,"value":"pending"},{"do":"dbExpectStock","item":"Desk Lamp","plus":0,"relativeTo":"pending-East","warehouse":"East"},{"do":"dbExpectStock","item":"Desk Lamp","plus":0,"relativeTo":"pending-West","warehouse":"West"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","ifAvailable":true},{"do":"click","unlessVisible":"admin-revenue"},{"do":"expectNumber","plus":0,"relativeTo":"pending-revenue"}],"source":"scenarios/progression-order-return-boundary.json","stableKey":"ecommerce.returns-pricing.cancellation-and-return.3f","statedBy":"Only shipped items can be returned.","withheld":null},{"category":"production","checkGroupId":"cancellation-and-return","criterionId":"3c","description":"returning a shipped item restores stock and revenue and marks the item returned","featureId":330,"featureName":"Completed order return","note":null,"packId":"ecommerce.l3.order-returns-features","points":3,"provenBy":null,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.progression.fulfilment-queue"],"role":"feature","semantics":[{"do":"click"},{"contains":"Keyboard","containsText":"returned","do":"expect","ignoreCase":true},{"do":"freshClient"},{"do":"signIn","name":"return-complete"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click"},{"contains":"Keyboard","containsText":"returned","do":"expect","ignoreCase":true},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","unlessVisible":"admin-revenue"},{"do":"expectNumber","plus":0,"relativeTo":"return-revenue-before"},{"do":"click","ifAvailable":true},{"do":"click","ifAvailable":true},{"do":"dbExpectStock","item":"Keyboard","plus":0,"relativeTo":"return-stock-before"}],"source":"scenarios/progression-order-return-complete.json","stableKey":"ecommerce.returns-pricing.cancellation-and-return.3c","statedBy":"An accepted return marks the item as returned, restores stock, and reduces revenue by the price paid.","withheld":null},{"category":"production","checkGroupId":"order-support-ownership","criterionId":"614b","description":"another customer cannot attach or inspect the owner's order","featureId":614,"featureName":"Order support ownership boundary","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"provenBy":null,"requiresFeatures":["ecommerce.progression.order-support"],"role":"guarantee","semantics":[{"absent":true,"contains":"Desk Lamp","do":"expect"},{"action":"linkSupportOrder","authentication":"actor","do":"callAction","input":{"attribute":"data-action-input","testid":"support-link-order"},"namedAction":{"args":[0,0],"id":"linkSupportOrder","method":"POST","params":[{"in":"path","name":"caseId","placeholder":"{caseId}","wireType":"u64"},{"in":"body","name":"orderId","wireType":"u64"}],"path":"/api/support/cases/{caseId}/order","reducer":"link_support_order"}},{"do":"expectActionOutcome","outcome":"accepted"},{"contains":"Desk Lamp","do":"expectElementCount","equals":1},{"action":"linkSupportOrder","authentication":"actor","do":"callAction","from":"owner","input":{"attribute":"data-action-input","overrides":{"caseId":{"actor":"other","attribute":"data-entity-id","contains":"Other order case","testid":"support-ticket"}},"testid":"support-link-order"},"namedAction":{"args":[0,0],"id":"linkSupportOrder","method":"POST","params":[{"in":"path","name":"caseId","placeholder":"{caseId}","wireType":"u64"},{"in":"body","name":"orderId","wireType":"u64"}],"path":"/api/support/cases/{caseId}/order","reducer":"link_support_order"}},{"do":"expectActionOutcome","outcome":"refused"},{"do":"freshClient"},{"do":"signIn","name":"order-boundary-other"},{"do":"click"},{"absent":true,"contains":"Desk Lamp","do":"expect"},{"contains":"Desk Lamp","do":"expectElementCount","equals":1}],"source":"scenarios/progression-order-support-boundary.json","stableKey":"ecommerce.spec.access-control.order-support-ownership.614b","statedBy":"A customer cannot attach or inspect another customer's order.","withheld":null},{"category":"feature","checkGroupId":"order-support-owned","criterionId":"614a","description":"the customer can link their order and staff can inspect it","featureId":614,"featureName":"Owned order support link","note":null,"packId":"ecommerce.progression.order-support","points":3,"provenBy":null,"role":"feature","semantics":[{"do":"click"},{"do":"click"},{"do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"do":"click","unlessVisible":"support-assignee"},{"do":"click","ifAvailable":true,"unlessVisible":"support-assignee"},{"contains":"Desk Lamp","do":"expect"}],"source":"scenarios/progression-order-support-owned.json","stableKey":"ecommerce.progression.order-support.order-support-owned.614a","statedBy":"A customer can attach one of their orders to a support case.","withheld":null},{"category":"feature","checkGroupId":"personalized-recommendations","criterionId":"403a","description":"recommendations follow the customer's categories, global sales, and name tie-break","featureId":403,"featureName":"Recommendations use customer activity","note":null,"packId":"ecommerce.progression.personalized-recommendations","points":4,"provenBy":null,"role":"feature","semantics":[{"contains":"Headphones","do":"expect"},{"do":"expectNumber","equals":1},{"do":"expectSequence","equals":["Gaming Mouse","Laptop Stand","Webcam"]}],"source":"scenarios/progression-personalized-recommendations.json","stableKey":"ecommerce.progression.personalized-recommendations.personalized-recommendations.403a","statedBy":"Order the remaining items by global units sold, highest first, then by item name.","withheld":null},{"category":"production","checkGroupId":"recommendation-profile-isolation","criterionId":"403b","description":"one customer's activity does not replace another customer's recommendations","featureId":403,"featureName":"Recommendations use customer activity","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"provenBy":null,"requiresFeatures":["ecommerce.progression.personalized-recommendations"],"role":"guarantee","semantics":[{"do":"click"},{"do":"waitUntilAbsent"},{"do":"expectNumber","equals":1},{"do":"expectSequence","equals":["Gaming Mouse","Laptop Stand","Webcam"]}],"source":"scenarios/progression-personalized-recommendations.json","stableKey":"ecommerce.spec.access-control.recommendation-profile-isolation.403b","statedBy":"Customer recommendation profiles are isolated.","withheld":null},{"category":"production","checkGroupId":"price-history","criterionId":"4c","description":"a price change updates an open cart and direct checkout persists the new total","featureId":420,"featureName":"Open cart price changes","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.progression.price-history-specifications","points":3,"provenBy":null,"requiresFeatures":["ecommerce.feature.checkout","ecommerce.l2.price-history-features"],"role":"guarantee","semantics":[{"do":"fill","enter":true,"text":"Desk Lamp"},{"do":"click"},{"do":"click"},{"do":"expectNumber","equals":42},{"do":"fill","text":"52.00"},{"do":"click"},{"do":"expectNumber","equals":52},{"action":"checkout","do":"callAction","namedAction":{"args":[],"id":"checkout","method":"POST","path":"/api/checkout","reducer":"checkout"}},{"do":"expectActionOutcome","outcome":"accepted"},{"do":"freshClient"},{"do":"signIn","name":"price-cart"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click"},{"contains":"Desk Lamp","count":1,"do":"expect"},{"do":"expectNumber","equals":52}],"source":"scenarios/progression-price-cart-checkout.json","stableKey":"ecommerce.returns-pricing.price-history.4c","statedBy":"The public catalog and every open cart show the new price without a reload. Checkout uses the current price.","withheld":null},{"category":"feature","checkGroupId":"product-bundles","criterionId":"740a","description":"a saved bundle shows the exact price and component quantities after reopening the application","featureId":740,"featureName":"Bundle definitions","note":null,"packId":"ecommerce.feature.product-bundles","points":2,"provenBy":null,"role":"feature","semantics":[{"do":"fill","text":"Office bundle"},{"do":"fill","text":"75.00"},{"do":"fill","text":"[{\"item\":\"Keyboard\",\"quantity\":2},{\"item\":\"Desk Lamp\",\"quantity\":1}]"},{"do":"click"},{"contains":"Office bundle","do":"expect"},{"do":"reload"},{"do":"click","unlessVisible":"bundle-card"},{"do":"expectNumber","equals":75},{"do":"expectElementCount","equals":2},{"attribute":"data-quantity","contains":"Keyboard","do":"expect","value":"2"},{"attribute":"data-quantity","contains":"Desk Lamp","do":"expect","value":"1"}],"source":"scenarios/progression-product-bundles.json","stableKey":"ecommerce.feature.product-bundles.product-bundles.740a","statedBy":null,"withheld":null},{"category":"production","checkGroupId":"bundle-743","criterionId":"743a","description":"a customer cannot replace a staff-created bundle through the application write","featureId":743,"featureName":"Bundle management authorization","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.bundle-integrity","points":3,"provenBy":null,"requiresFeatures":["ecommerce.feature.product-bundles"],"role":"guarantee","semantics":[{"do":"fill","text":"1.00"},{"action":"saveBundle","do":"callAction","from":"admin","input":{"attribute":"data-bundle-save-input","testid":"bundle-save"},"namedAction":{"args":["Protected bundle",1,"[{\"item\":\"Keyboard\",\"quantity\":1}]"],"id":"saveBundle","params":[{"in":"body","name":"name"},{"in":"body","name":"price"},{"in":"body","name":"componentsJson"}],"path":"/api/bundles","reducer":"save_bundle"}},{"do":"expectActionOutcome","outcome":"application-refused"},{"do":"reload"},{"do":"click","unlessVisible":"bundle-card"},{"do":"expectNumber","equals":75},{"attribute":"data-quantity","contains":"Keyboard","do":"expect","value":"2"}],"source":"scenarios/progression-product-bundles.json","stableKey":"ecommerce.spec.bundle-integrity.bundle-743.743a","statedBy":null,"withheld":null},{"category":"feature","checkGroupId":"promotion-checkout-active","criterionId":"621a","description":"an active promotion changes checkout and is recorded on the order","featureId":621,"featureName":"Bounded promotions at checkout","note":null,"packId":"ecommerce.progression.promotion-checkout","points":3,"provenBy":null,"role":"feature","semantics":[{"do":"click"},{"do":"click"},{"do":"fill","text":"LIVE10"},{"do":"click"},{"do":"click"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click"},{"do":"expectNumber","equals":8.9}],"source":"scenarios/progression-promotion-checkout.json","stableKey":"ecommerce.progression.promotion-checkout.promotion-checkout-active.621a","statedBy":"An active promotion applies to the cart and the order records its discount.","withheld":null},{"category":"feature","checkGroupId":"promotion-checkout-expired","criterionId":"621b","description":"an expired promotion is refused","featureId":621,"featureName":"Bounded promotions at checkout","note":null,"packId":"ecommerce.progression.promotion-checkout","points":2,"provenBy":null,"role":"feature","semantics":[{"do":"click"},{"do":"click"},{"do":"fill","text":"OLD10"},{"do":"click"},{"do":"expect"}],"source":"scenarios/progression-promotion-checkout.json","stableKey":"ecommerce.progression.promotion-checkout.promotion-checkout-expired.621b","statedBy":"Expired promotions cannot be applied.","withheld":null},{"category":"feature","checkGroupId":"promotion-checkout-exhausted","criterionId":"621c","description":"a fully redeemed promotion is refused","featureId":621,"featureName":"Bounded promotions at checkout","note":null,"packId":"ecommerce.progression.promotion-checkout","points":2,"provenBy":null,"role":"feature","semantics":[{"do":"click"},{"do":"click"},{"do":"fill","text":"ONCE10"},{"do":"click"},{"do":"click"},{"do":"click"},{"do":"click"},{"do":"fill","text":"ONCE10"},{"do":"click"},{"do":"expect"}],"source":"scenarios/progression-promotion-checkout.json","stableKey":"ecommerce.progression.promotion-checkout.promotion-checkout-exhausted.621c","statedBy":"A promotion cannot be used after its redemption limit is reached.","withheld":null},{"category":"feature","checkGroupId":"promotion-report-redemptions","criterionId":"622a","description":"the promotion report has the exact redemption count","featureId":622,"featureName":"Exact promotion totals","note":null,"packId":"ecommerce.progression.promotion-reporting","points":1,"provenBy":null,"role":"feature","semantics":[{"do":"expectNumber","equals":1}],"source":"scenarios/progression-promotion-reporting.json","stableKey":"ecommerce.progression.promotion-reporting.promotion-report-redemptions.622a","statedBy":"Promotion redemption counts match orders that used the promotion.","withheld":null},{"category":"feature","checkGroupId":"promotion-report-revenue","criterionId":"622b","description":"the promotion report has the exact discounted revenue","featureId":622,"featureName":"Exact promotion totals","note":null,"packId":"ecommerce.progression.promotion-reporting","points":2,"provenBy":null,"role":"feature","semantics":[{"do":"expectNumber","equals":80.1}],"source":"scenarios/progression-promotion-reporting.json","stableKey":"ecommerce.progression.promotion-reporting.promotion-report-revenue.622b","statedBy":"Promotion revenue after discounts matches orders that used the promotion.","withheld":null},{"category":"feature","checkGroupId":"promotion-rule-values","criterionId":"620a","description":"staff can save every bounded promotion value","featureId":620,"featureName":"Staff-managed promotion rules","note":null,"packId":"ecommerce.progression.promotion-rules","points":2,"provenBy":null,"role":"feature","semantics":[{"do":"click","unlessVisible":"promotion-code"},{"do":"fill","text":"SAVE10"},{"do":"fill","text":"10"},{"do":"fill","text":"2099-01-01"},{"do":"fill","text":"2099-12-31"},{"do":"fill","text":"2"},{"do":"click"},{"do":"expectNumber","equals":10},{"contains":"2099-01-01","do":"expect"},{"contains":"2099-12-31","do":"expect"},{"do":"expectNumber","equals":2}],"source":"scenarios/progression-promotion-rules.json","stableKey":"ecommerce.progression.promotion-rules.promotion-rule-values.620a","statedBy":"Staff can create a promotion code with a discount, active period, and redemption limit.","withheld":null},{"category":"production","checkGroupId":"promotion-management-boundary","criterionId":"620b","description":"customers cannot open promotion management","featureId":620,"featureName":"Staff-managed promotion rules","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"provenBy":null,"requiresFeatures":["ecommerce.progression.promotion-rules"],"role":"guarantee","semantics":[{"do":"click","unlessVisible":"promotion-code"},{"do":"fill","text":"ACCESS10"},{"do":"fill","text":"10"},{"do":"fill","text":"2099-01-01"},{"do":"fill","text":"2099-12-31"},{"do":"fill","text":"2"},{"do":"click"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"do":"click","ifAvailable":true,"unlessVisible":"promotion-code"},{"do":"click","unlessVisible":"promotion-code"},{"contains":"ACCESS10","do":"expect"},{"absent":true,"do":"expect"},{"do":"replayAs","from":"staff","match":"ACCESS10","namedAction":{"args":["ACCESS10",10,4070908800000000,4102444740000000,2],"id":"createPromotion","params":[{"in":"body","name":"code"},{"in":"body","name":"discountPercent"},{"in":"body","name":"startMicros"},{"in":"body","name":"endMicros"},{"in":"body","name":"usageLimit"}],"path":"/api/promotions","reducer":"create_promotion"},"swap":{"find":"ACCESS10","with":"HACK10"}},{"do":"expectReplayRejected"},{"absent":true,"contains":"HACK10","do":"expect"}],"source":"scenarios/progression-promotion-rules.json","stableKey":"ecommerce.spec.access-control.promotion-management-boundary.620b","statedBy":"Customers cannot manage promotion rules.","withheld":null},{"category":"feature","checkGroupId":"purchase-order","criterionId":"3c","description":"the purchase is recorded in the buyer's order history at the price paid","featureId":3,"featureName":"Purchase order history","note":null,"packId":"ecommerce.feature.purchasing","points":1,"provenBy":null,"role":"feature","semantics":[{"do":"click"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"contains":"Coffee Grinder","do":"expect"},{"do":"expectNumber","equals":64}],"source":"scenarios/progression-purchasing.json","stableKey":"ecommerce.feature.purchasing.purchase-order.3c","statedBy":"A purchase creates an order for the customer at the price paid.","withheld":null},{"category":"feature","checkGroupId":"recommendation-feedback","criterionId":"504a","description":"dismissing a recommendation removes it from the customer view","featureId":504,"featureName":"Recommendation dismissal","note":null,"packId":"ecommerce.progression.recommendation-feedback","points":2,"provenBy":null,"role":"feature","semantics":[{"absent":true,"contains":"Headphones","do":"expect"}],"source":"scenarios/progression-recommendation-feedback.json","stableKey":"ecommerce.progression.recommendation-feedback.recommendation-feedback.504a","statedBy":"Customers can dismiss a recommendation.","withheld":null},{"category":"production","checkGroupId":"recommendation-feedback-privacy","criterionId":"504b","description":"one customer's dismissal does not hide another customer's result","featureId":504,"featureName":"Recommendation dismissal","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"provenBy":null,"requiresFeatures":["ecommerce.progression.recommendation-feedback"],"role":"guarantee","semantics":[{"do":"waitUntilAbsent"},{"contains":"Headphones","do":"expect"}],"source":"scenarios/progression-recommendation-feedback.json","stableKey":"ecommerce.spec.access-control.recommendation-feedback-privacy.504b","statedBy":"Recommendation feedback belongs to one customer.","withheld":null},{"category":"production","checkGroupId":"recommendation-feedback-restart","criterionId":"504c","description":"a dismissed recommendation stays absent after reload and backend restart in a fresh browser","featureId":504,"featureName":"Recommendation dismissal","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.state-durability","points":2,"provenBy":null,"requiresFeatures":["ecommerce.progression.recommendation-feedback"],"role":"guarantee","semantics":[{"do":"reload"},{"do":"ensureSignedIn","name":"feedback-owner"},{"absent":true,"contains":"Headphones","do":"expect"},{"do":"restartBackend"},{"do":"freshClient"},{"do":"signIn","name":"feedback-owner"},{"do":"expect"},{"absent":true,"contains":"Headphones","do":"expect"}],"source":"scenarios/progression-recommendation-feedback.json","stableKey":"ecommerce.spec.state-durability.recommendation-feedback-restart.504c","statedBy":"A dismissed recommendation stays dismissed for that customer.","withheld":null},{"category":"production","checkGroupId":"review-eligibility-direct","criterionId":"618a","description":"a nonbuyer cannot submit or replace a review by claiming a buyer's username","featureId":618,"featureName":"Review access","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.progression.review-access-specifications","points":2,"provenBy":null,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.reviews"],"role":"guarantee","semantics":[{"action":"submitReview","do":"callAction","input":{"attribute":"data-buy-input","contains":"Keyboard","testid":"item-card"},"namedAction":{"args":[0,5,"Original buyer review"],"id":"submitReview","method":"POST","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"},{"in":"body","name":"rating"},{"in":"body","name":"comment"}],"path":"/api/items/:id/reviews","reducer":"submit_review"}},{"do":"expectActionOutcome","outcome":"accepted"},{"action":"submitReview","do":"callAction","input":{"attribute":"data-buy-input","contains":"Keyboard","testid":"item-card"},"namedAction":{"args":[0,5,"Nonbuyer review"],"id":"submitReview","method":"POST","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"},{"in":"body","name":"rating"},{"in":"body","name":"comment"}],"path":"/api/items/:id/reviews","reducer":"submit_review"}},{"do":"expectActionOutcome","outcome":"application-refused","routeProvenBy":"owner"},{"action":"submitReview","do":"callAction","input":{"attribute":"data-buy-input","contains":"Keyboard","testid":"item-card"},"namedAction":{"args":[0,5,"Forged buyer review","claim-review-owner"],"id":"submitReview","method":"POST","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"},{"in":"body","name":"rating"},{"in":"body","name":"comment"},{"in":"body","name":"username"}],"path":"/api/items/:id/reviews","reducer":"submit_review"}},{"do":"expectActionOutcome","outcome":"application-refused","routeProvenBy":"owner"},{"do":"freshClient"},{"do":"signIn","exact":true,"name":"claim-review-owner"},{"do":"openItem","item":"Keyboard"},{"contains":"Original buyer review","do":"expect"},{"absent":true,"contains":"Nonbuyer review","do":"expect"},{"absent":true,"contains":"Forged buyer review","do":"expect"}],"source":"scenarios/progression-review-access.json","stableKey":"ecommerce.progression.review-access-specifications.review-eligibility-direct.618a","statedBy":"Only a customer who bought an item can review it.","withheld":null},{"category":"production","checkGroupId":"stored-review-script","criterionId":"9180a","description":"review input is rejected or displayed without executing script in another customer session","featureId":9180,"featureName":"Stored review content","note":null,"observations":["unmentioned"],"packId":"ecommerce.progression.review-access-specifications","points":1,"provenBy":null,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.reviews"],"role":"guarantee","semantics":[{"action":"submitReview","do":"callAction","input":{"attribute":"data-buy-input","contains":"Keyboard","testid":"item-card"},"namedAction":{"args":[0,5,"Benign stored review"],"id":"submitReview","method":"POST","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"},{"in":"body","name":"rating"},{"in":"body","name":"comment"}],"path":"/api/items/:id/reviews","reducer":"submit_review"}},{"do":"expectActionOutcome","outcome":"accepted"},{"action":"submitReview","do":"callAction","input":{"attribute":"data-buy-input","contains":"Keyboard","testid":"item-card"},"namedAction":{"args":[0,5,"Stored review marker "],"id":"submitReview","method":"POST","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"},{"in":"body","name":"rating"},{"in":"body","name":"comment"}],"path":"/api/items/:id/reviews","reducer":"submit_review"}},{"do":"expectActionOutcome","outcome":"completed","routeProvenBy":"owner"},{"do":"openItem","item":"Keyboard"},{"contains":"Benign stored review","do":"expect"},{"do":"wait"},{"do":"expectNoScriptExecution"},{"do":"freshClient"},{"do":"signIn","name":"script-review-reader"},{"do":"armScriptCanary"},{"do":"openItem","item":"Keyboard"},{"contains":"Benign stored review","do":"expect"},{"do":"wait"},{"do":"expectNoScriptExecution"}],"source":"scenarios/progression-review-script.json","stableKey":"ecommerce.progression.review-access-specifications.stored-review-script.9180a","statedBy":null,"withheld":null},{"category":"production","checkGroupId":"search-ordering","criterionId":"402b","description":"active filters and text searches remain alphabetical after purchases; clearing them restores purchase ranking","featureId":402,"featureName":"Purchases preserve search ordering","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.search-ordering","points":1,"provenBy":null,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.progression.faceted-search"],"role":"guarantee","semantics":[{"do":"expectSequence","equals":["Air Purifier","Bluetooth Speaker","Coffee Grinder","Desk Lamp","Espresso Machine","Gaming Mouse","Headphones","Induction Cooktop","Keyboard","Laptop Stand"]},{"do":"fill","enter":true,"text":"e"},{"do":"fill","text":""},{"do":"click","ifAvailable":true},{"do":"expectSequence","equals":["Air Purifier","Bluetooth Speaker","Coffee Grinder","Desk Lamp","Espresso Machine","Gaming Mouse","Headphones","Keyboard","Mirrorless Camera","USB Cable"]},{"do":"fill","enter":true,"text":""},{"do":"expectSequence","equals":["Headphones","Air Purifier","Bluetooth Speaker","Coffee Grinder","Desk Lamp","Espresso Machine","Gaming Mouse","Induction Cooktop","Keyboard","Laptop Stand"]}],"source":"scenarios/progression-search-ordering.json","stableKey":"ecommerce.spec.search-ordering.search-ordering.402b","statedBy":"Active search and filter results use item-name order; clearing them restores purchase ranking","withheld":null},{"category":"production","checkGroupId":"shipping-accounting","criterionId":"202e","description":"shipping a purchased order does not deduct stock or add revenue again","featureId":202,"featureName":"Shipping preserves completed purchase accounting","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.progression.inventory-conservation-specifications","points":2,"provenBy":null,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.warehouse-admin","ecommerce.progression.fulfilment-queue"],"role":"guarantee","semantics":[{"as":"stock-before-purchase","do":"dbRecordStock","item":"Keyboard"},{"as":"revenue-before-purchase","do":"recordNumber"},{"do":"click"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"do":"expect","ignoreCase":true,"value":"pending"},{"do":"dbExpectStock","item":"Keyboard","plus":-1,"relativeTo":"stock-before-purchase"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","ifAvailable":true},{"do":"expectNumber","plus":89,"relativeTo":"revenue-before-purchase"},{"as":"revenue-before-ship","do":"recordNumber"},{"as":"East-before-ship","do":"dbRecordStock","item":"Keyboard","warehouse":"East"},{"as":"West-before-ship","do":"dbRecordStock","item":"Keyboard","warehouse":"West"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"do":"click","ifAvailable":true},{"action":"ship","do":"callAction","from":"customer","input":{"attribute":"data-ship-input","contains":"Keyboard","testid":"order-item"},"namedAction":{"args":[0],"id":"ship","params":[{"in":"body","name":"orderId","wireType":"u64"}],"path":"/api/fulfilment/ship","reducer":"ship_order"}},{"do":"expectActionOutcome","outcome":"accepted"},{"do":"reload"},{"do":"ensureSignedIn","name":"shipping-accounting"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"do":"expect","ignoreCase":true,"value":"shipped"},{"do":"dbExpectStock","item":"Keyboard","plus":0,"relativeTo":"East-before-ship","warehouse":"East"},{"do":"dbExpectStock","item":"Keyboard","plus":0,"relativeTo":"West-before-ship","warehouse":"West"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","ifAvailable":true},{"do":"expectNumber","plus":0,"relativeTo":"revenue-before-ship"}],"source":"scenarios/progression-shipping-accounting.json","stableKey":"ecommerce.inventory-operations.shipping-accounting.202e","statedBy":"Shipping preserves the stock and revenue recorded for the purchase.","withheld":null},{"category":"production","checkGroupId":"signed-out-purchase","criterionId":"3a","description":"using the purchase control while signed out does not buy an item","featureId":3,"featureName":"Buying","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":1,"provenBy":null,"requiresFeatures":["ecommerce.feature.purchasing"],"role":"guarantee","semantics":[{"as":"keyboard-before-guest","do":"recordNumber"},{"do":"click","ifAvailable":true},{"do":"reload"},{"do":"click","ifAvailable":true},{"do":"click","ifAvailable":true},{"do":"expectNumber","plus":0,"relativeTo":"keyboard-before-guest"}],"source":"scenarios/progression-signed-out-purchase.json","stableKey":"ecommerce.spec.access-control.signed-out-purchase.3a","statedBy":"Unauthenticated callers cannot purchase.","withheld":null},{"category":"feature","checkGroupId":"split-tender-refunds-751","criterionId":"751a","description":"Full refund restores each original payment portion","featureId":751,"featureName":"Full refund restores each original payment portion","note":null,"packId":"ecommerce.feature.split-tender-refunds","points":2,"provenBy":null,"requiresFeatures":["ecommerce.feature.split-tender-refunds","ecommerce.feature.store-credit","ecommerce.progression.support-refunds"],"role":"feature","semantics":[{"do":"click"},{"do":"freshClient"},{"do":"signIn","name":"credit-owner-751"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click"},{"contains":"Desk Lamp","do":"expectElementCount","equals":1},{"do":"expectNumber","equals":42},{"do":"expectNumber","equals":10},{"do":"expectNumber","equals":32},{"do":"click"},{"attribute":"aria-busy","do":"expect","value":"false"},{"do":"expectNumber","equals":10}],"source":"scenarios/progression-split-tender-refunds.json","stableKey":"ecommerce.feature.split-tender-refunds.split-tender-refunds-751.751a","statedBy":null,"withheld":null},{"category":"production","checkGroupId":"production-756","criterionId":"756a","description":"Concurrent refunds restore the original credit and external amounts once, including after restart","featureId":756,"featureName":"Concurrent refunds do not duplicate credit after restart","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.split-tender-refunds","points":2,"provenBy":null,"requiresFeatures":["ecommerce.feature.split-tender-refunds","ecommerce.feature.store-credit","ecommerce.progression.support-refunds"],"role":"guarantee","semantics":[{"action":"supportRefund","do":"callConcurrently","from":"staff","input":{"attribute":"data-refund-input","contains":"Split refund 756","testid":"support-ticket"},"namedAction":{"args":[0],"id":"supportRefund","method":"POST","params":[{"in":"path","name":"caseId","placeholder":"{caseId}","wireType":"u64"}],"path":"/api/support/cases/{caseId}/refund","reducer":"support_refund"}},{"do":"expectCallOutcomes"},{"do":"freshClient"},{"do":"signIn","name":"credit-owner-756"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click"},{"contains":"Desk Lamp","do":"expectElementCount","equals":1},{"do":"expectNumber","equals":42},{"do":"expectNumber","equals":10},{"do":"expectNumber","equals":32},{"do":"click"},{"attribute":"aria-busy","do":"expect","value":"false"},{"do":"expectNumber","equals":10},{"do":"restartBackend"},{"do":"freshClient"},{"do":"signIn","name":"credit-owner-756"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click"},{"contains":"Desk Lamp","do":"expectElementCount","equals":1},{"do":"expectNumber","equals":42},{"do":"expectNumber","equals":10},{"do":"expectNumber","equals":32},{"do":"click"},{"attribute":"aria-busy","do":"expect","value":"false"},{"do":"expectNumber","equals":10}],"source":"scenarios/progression-split-tender-refunds.json","stableKey":"ecommerce.spec.split-tender-refunds.production-756.756a","statedBy":null,"withheld":null},{"category":"feature","checkGroupId":"staff-access","criterionId":"601a","description":"staff and administrators can sign in and open staff tools","featureId":601,"featureName":"Staff access","note":null,"packId":"ecommerce.progression.staff-access","points":2,"provenBy":null,"role":"feature","semantics":[{"do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"do":"click"},{"do":"expect"},{"do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click"},{"do":"expect"}],"source":"scenarios/progression-staff-access.json","stableKey":"ecommerce.progression.staff-access.staff-access.601a","statedBy":"Staff and administrators can sign in and use staff areas.","withheld":null},{"category":"production","checkGroupId":"staff-area-boundary","criterionId":"601b","description":"customers cannot open staff tools","featureId":601,"featureName":"Staff access","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"provenBy":null,"requiresFeatures":["ecommerce.progression.staff-access"],"role":"guarantee","semantics":[{"do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"do":"click"},{"do":"expect"},{"do":"signIn","exact":true,"name":"customer","password":"stackbench-customer-2026"},{"do":"click","ifAvailable":true},{"absent":true,"do":"expect"}],"source":"scenarios/progression-staff-access.json","stableKey":"ecommerce.spec.access-control.staff-area-boundary.601b","statedBy":"Customers cannot open staff tools.","withheld":null},{"category":"feature","checkGroupId":"staff-activity","criterionId":"624a","description":"an administrative change records its actor, action, subject, and time","featureId":624,"featureName":"Attributable staff activity","note":null,"packId":"ecommerce.progression.staff-activity","points":3,"provenBy":null,"role":"feature","semantics":[{"do":"click"},{"do":"click"},{"contains":"Activity Mug","do":"expect"},{"contains":"admin","do":"expect"},{"contains":"creat","do":"expect"},{"contains":"Activity Mug","do":"expect"},{"do":"expect"}],"source":"scenarios/progression-staff-activity.json","stableKey":"ecommerce.progression.staff-activity.staff-activity.624a","statedBy":"Each administrative change identifies its actor, action, subject, and time.","withheld":null},{"category":"production","checkGroupId":"staff-activity-privacy","criterionId":"624b","description":"customers cannot open staff activity history","featureId":624,"featureName":"Attributable staff activity","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"provenBy":null,"requiresFeatures":["ecommerce.progression.staff-activity"],"role":"guarantee","semantics":[{"absent":true,"do":"expect"}],"source":"scenarios/progression-staff-activity.json","stableKey":"ecommerce.spec.access-control.staff-activity-privacy.624b","statedBy":"Customers cannot open staff activity history.","withheld":null},{"category":"feature","checkGroupId":"staff-roles","criterionId":"621c","description":"an administrator can assign a staff role","featureId":621,"featureName":"Staff roles","note":null,"packId":"ecommerce.progression.staff-roles","points":1,"provenBy":null,"role":"feature","semantics":[{"do":"expect","value":"inventory"}],"source":"scenarios/progression-staff-roles.json","stableKey":"ecommerce.progression.staff-roles.staff-roles.621c","statedBy":"An administrator can assign a role to an existing staff account.","withheld":null},{"category":"production","checkGroupId":"staff-role-reload","criterionId":"621a","description":"an assigned staff role survives reload and backend restart in a fresh browser","featureId":621,"featureName":"Staff roles","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.state-durability","points":2,"provenBy":null,"requiresFeatures":["ecommerce.progression.staff-roles"],"role":"guarantee","semantics":[{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","ifAvailable":true,"unlessVisible":"staff-role-account-staff"},{"do":"expect","value":"inventory"},{"do":"restartBackend"},{"do":"freshClient"},{"do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","unlessVisible":"staff-role-account-staff"},{"do":"expect","value":"inventory"}],"source":"scenarios/progression-staff-roles.json","stableKey":"ecommerce.spec.state-durability.staff-role-reload.621a","statedBy":"Assigned staff roles persist.","withheld":null},{"category":"production","checkGroupId":"staff-role-boundary","criterionId":"621b","description":"a staff member cannot assign roles through the UI or a replayed request","featureId":621,"featureName":"Staff roles","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"provenBy":null,"requiresFeatures":["ecommerce.progression.staff-roles"],"role":"guarantee","semantics":[{"do":"reload"},{"do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"expect"},{"do":"click","unlessVisible":"staff-role-account-staff"},{"do":"fill","text":"staff"},{"do":"click"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","ifAvailable":true,"unlessVisible":"staff-role-account-staff"},{"do":"expect","value":"staff"},{"do":"reload"},{"do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"do":"click","ifAvailable":true},{"absent":true,"do":"expect"},{"do":"replayAs","from":"replayAdmin","match":"role","namedAction":{"args":[0,"inventory"],"id":"assignStaffRole","method":"PUT","params":[{"in":"path","name":"accountId","placeholder":":id","wireType":"u64"},{"in":"body","name":"role"}],"path":"/api/staff/:id/role","reducer":"assign_staff_role"},"namedTarget":{"attribute":"data-account-id","testid":"staff-role-account-staff","valueType":"string"},"swap":{"find":"\"role\":\"staff\"","with":"\"role\":\"inventory\""}},{"do":"expectReplayRejected"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","ifAvailable":true,"unlessVisible":"staff-role-account-staff"},{"do":"expect","value":"staff"}],"source":"scenarios/progression-staff-roles.json","stableKey":"ecommerce.spec.access-control.staff-role-boundary.621b","statedBy":"A staff member cannot assign or change roles.","withheld":null},{"category":"production","checkGroupId":"staff-role-revocation","criterionId":"621d","description":"removing administrator access blocks a previously authorized session without changing the target role","featureId":621,"featureName":"Staff roles","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"provenBy":null,"requiresFeatures":["ecommerce.progression.staff-roles"],"role":"guarantee","semantics":[{"do":"reload"},{"do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","unlessVisible":"staff-role-account-staff"},{"do":"replayAs","from":"roleAdmin","match":"__role-revocation-named-action__","namedAction":{"args":[0,"admin"],"id":"assignStaffRole","method":"PUT","params":[{"in":"path","name":"accountId","placeholder":":id","wireType":"u64"},{"in":"body","name":"role"}],"path":"/api/staff/:id/role","reducer":"assign_staff_role"},"namedTarget":{"attribute":"data-account-id","testid":"staff-role-account-staff","valueType":"string"}},{"do":"expectReplayCompleted","requireAccepted":true},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","ifAvailable":true,"unlessVisible":"staff-role-account-staff"},{"do":"expect","value":"admin"},{"do":"reload"},{"do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"do":"replayAs","from":"roleAdmin","match":"__role-revocation-named-action__","namedAction":{"args":[0,"admin"],"id":"assignStaffRole","method":"PUT","params":[{"in":"path","name":"accountId","placeholder":":id","wireType":"u64"},{"in":"body","name":"role"}],"path":"/api/staff/:id/role","reducer":"assign_staff_role"},"namedTarget":{"attribute":"data-account-id","testid":"staff-role-account-staff","valueType":"string"}},{"do":"expectReplayCompleted","requireAccepted":true},{"do":"replayAs","from":"roleAdmin","match":"__role-revocation-named-action__","namedAction":{"args":[0,"staff"],"id":"assignStaffRole","method":"PUT","params":[{"in":"path","name":"accountId","placeholder":":id","wireType":"u64"},{"in":"body","name":"role"}],"path":"/api/staff/:id/role","reducer":"assign_staff_role"},"namedTarget":{"attribute":"data-account-id","testid":"staff-role-account-staff","valueType":"string"}},{"do":"expectReplayCompleted","requireAccepted":true},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","ifAvailable":true,"unlessVisible":"staff-role-account-staff"},{"do":"expect","value":"staff"},{"do":"replayAs","from":"roleAdmin","match":"__role-revocation-named-action__","namedAction":{"args":[0,"admin"],"id":"assignStaffRole","method":"PUT","params":[{"in":"path","name":"accountId","placeholder":":id","wireType":"u64"},{"in":"body","name":"role"}],"path":"/api/staff/:id/role","reducer":"assign_staff_role"},"namedTarget":{"attribute":"data-account-id","testid":"staff-role-account-staff","valueType":"string"}},{"do":"expectReplayRejected"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","ifAvailable":true,"unlessVisible":"staff-role-account-staff"},{"do":"expect","value":"staff"}],"source":"scenarios/progression-staff-roles.json","stableKey":"ecommerce.spec.access-control.staff-role-revocation.621d","statedBy":"Only the admin role grants administrator access.","withheld":null},{"category":"feature","checkGroupId":"stock-alert-delivery","criterionId":"631c","description":"restored stock sends the requested alert","featureId":631,"featureName":"Stock alert delivery","note":null,"packId":"ecommerce.progression.stock-alerts","points":1,"provenBy":null,"requiresFeatures":["ecommerce.feature.warehouse-admin"],"role":"feature","semantics":[{"do":"freshClient"},{"do":"signIn","name":"stock-subscriber"},{"do":"click","unlessVisible":"notifications-panel"},{"attribute":"aria-busy","do":"expect","value":"false"},{"contains":"Air Purifier","do":"expectElementCount","equals":0},{"do":"click"},{"action":"restock","do":"callAction","input":{"attribute":"data-restock-input","contains":"Air Purifier","testid":"admin-location-row"},"namedAction":{"args":[0,0,1],"id":"restock","params":[{"in":"body","name":"itemId","wireType":"u64"},{"in":"body","name":"warehouseId","wireType":"u64"},{"in":"body","name":"quantity"}],"path":"/api/admin/restock","reducer":"admin_restock"}},{"do":"expectActionOutcome","outcome":"accepted"},{"do":"wait"},{"do":"freshClient"},{"do":"signIn","name":"stock-subscriber"},{"do":"click","unlessVisible":"notifications-panel"},{"attribute":"aria-busy","do":"expect","value":"false"},{"contains":"Air Purifier","do":"expect"}],"source":"scenarios/progression-stock-alert-delivery.json","stableKey":"ecommerce.progression.stock-alerts.stock-alert-delivery.631c","statedBy":"Show an alert when stock returns.","withheld":null},{"category":"production","checkGroupId":"stock-alert-deduplication","criterionId":"631a","description":"restored stock sends one alert and later restocks do not duplicate it","featureId":631,"featureName":"Private one-time stock alerts","note":"Sample a fresh account view 10 seconds after the second accepted restock. This catches persistent duplicates delivered by that sample, not all later or transient duplicates.","observations":["requested","unmentioned"],"packId":"ecommerce.spec.transactional-integrity","points":2,"provenBy":null,"requiresFeatures":["ecommerce.feature.warehouse-admin","ecommerce.progression.stock-alerts"],"role":"guarantee","semantics":[{"do":"freshClient"},{"do":"signIn","name":"stock-subscriber"},{"do":"click","unlessVisible":"notifications-panel"},{"attribute":"aria-busy","do":"expect","value":"false"},{"contains":"Air Purifier","do":"expectElementCount","equals":1},{"action":"restock","do":"callAction","input":{"attribute":"data-restock-input","contains":"Air Purifier","testid":"admin-location-row"},"namedAction":{"args":[0,0,1],"id":"restock","params":[{"in":"body","name":"itemId","wireType":"u64"},{"in":"body","name":"warehouseId","wireType":"u64"},{"in":"body","name":"quantity"}],"path":"/api/admin/restock","reducer":"admin_restock"}},{"do":"expectActionOutcome","outcome":"accepted"},{"do":"wait"},{"do":"freshClient"},{"do":"signIn","name":"stock-subscriber"},{"do":"click","unlessVisible":"notifications-panel"},{"attribute":"aria-busy","do":"expect","value":"false"},{"contains":"Air Purifier","do":"expectElementCount","equals":1}],"source":"scenarios/progression-stock-alerts.json","stableKey":"ecommerce.spec.transactional-integrity.stock-alert-deduplication.631a","statedBy":"A stock request creates one alert when stock returns.","withheld":null},{"category":"production","checkGroupId":"stock-alert-privacy","criterionId":"631b","description":"a customer who did not request the alert cannot see it","featureId":631,"featureName":"Private one-time stock alerts","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":1,"provenBy":null,"requiresFeatures":["ecommerce.feature.warehouse-admin","ecommerce.progression.stock-alerts"],"role":"guarantee","semantics":[{"do":"freshClient"},{"do":"signIn","name":"stock-subscriber"},{"do":"click","unlessVisible":"notifications-panel"},{"attribute":"aria-busy","do":"expect","value":"false"},{"contains":"Air Purifier","do":"expect"},{"do":"freshClient"},{"do":"signIn","name":"stock-other"},{"do":"click","unlessVisible":"notifications-panel"},{"attribute":"aria-busy","do":"expect","value":"false"},{"absent":true,"contains":"Air Purifier","do":"expect"}],"source":"scenarios/progression-stock-alerts.json","stableKey":"ecommerce.spec.access-control.stock-alert-privacy.631b","statedBy":"Stock alerts are private to the requesting customer.","withheld":null},{"category":"production","checkGroupId":"stock-limit","criterionId":"3d","description":"an item sells out visibly, and a further purchase is refused without changing stock","featureId":3,"featureName":"Buying","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.concurrency-safety","points":2,"provenBy":null,"requiresFeatures":["ecommerce.feature.purchasing"],"role":"guarantee","semantics":[{"do":"click"},{"do":"wait"},{"do":"click"},{"do":"wait"},{"do":"click"},{"do":"expectNumber","equals":0},{"do":"expect"},{"action":"buy","do":"callAction","input":{"attribute":"data-buy-input","contains":"Desk Lamp","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"}},{"do":"expectActionOutcome","outcome":"validation-refused"},{"do":"reload"},{"do":"ensureSignedIn","name":"eli"},{"do":"expectNumber","equals":0}],"source":"scenarios/progression-stock-limit.json","stableKey":"ecommerce.spec.concurrency-safety.stock-limit.3d","statedBy":"an item with zero stock cannot be bought","withheld":null},{"category":"feature","checkGroupId":"store-credit-750","criterionId":"750a","description":"Credit checkout records both payment portions","featureId":750,"featureName":"Credit checkout records both payment portions","note":null,"packId":"ecommerce.feature.store-credit","points":2,"provenBy":null,"role":"feature","semantics":[{"do":"click"},{"do":"freshClient"},{"do":"signIn","name":"credit-owner-750"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"contains":"Desk Lamp","do":"expectElementCount","equals":1},{"do":"expectNumber","equals":10},{"do":"expectNumber","equals":32},{"do":"expectNumber","equals":42},{"do":"click","unlessVisible":"credit-panel"},{"attribute":"aria-busy","do":"expect","value":"false"},{"do":"expectNumber","equals":0}],"source":"scenarios/progression-store-credit.json","stableKey":"ecommerce.feature.store-credit.store-credit-750.750a","statedBy":null,"withheld":null},{"category":"production","checkGroupId":"production-752","criterionId":"752a","description":"Repeating a grant reference does not increase the balance twice","featureId":752,"featureName":"Repeating a grant reference does not increase the balance twice","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.store-credit","points":2,"provenBy":null,"requiresFeatures":["ecommerce.feature.store-credit"],"role":"guarantee","semantics":[{"action":"grantCredit","do":"callAction","from":"staff","input":{"attribute":"data-action-input","overrides":{"accountId":{"actor":"owner","attribute":"data-account-id","testid":"credit-panel"}},"testid":"credit-grant"},"namedAction":{"args":[0,1000,""],"id":"grantCredit","method":"POST","params":[{"in":"body","name":"accountId","wireType":"u64"},{"in":"body","name":"amountMinor"},{"in":"body","name":"reference"}],"path":"/api/staff/credit","reducer":"grant_credit"}},{"do":"expectActionOutcome","outcome":"completed"},{"do":"freshClient"},{"do":"signIn","name":"credit-owner-752"},{"do":"click","unlessVisible":"credit-panel"},{"attribute":"aria-busy","do":"expect","value":"false"},{"do":"expectNumber","equals":10}],"source":"scenarios/progression-store-credit.json","stableKey":"ecommerce.spec.store-credit.production-752.752a","statedBy":null,"withheld":null},{"category":"production","checkGroupId":"production-753","criterionId":"753a","description":"A customer cannot grant credit","featureId":753,"featureName":"A customer cannot grant credit","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.store-credit","points":2,"provenBy":null,"requiresFeatures":["ecommerce.feature.store-credit"],"role":"guarantee","semantics":[{"do":"fill","text":"unauthorized-credit-753"},{"action":"grantCredit","do":"callAction","from":"staff","input":{"attribute":"data-action-input","overrides":{"accountId":{"actor":"owner","attribute":"data-account-id","testid":"credit-panel"}},"testid":"credit-grant"},"namedAction":{"args":[0,1000,""],"id":"grantCredit","method":"POST","params":[{"in":"body","name":"accountId","wireType":"u64"},{"in":"body","name":"amountMinor"},{"in":"body","name":"reference"}],"path":"/api/staff/credit","reducer":"grant_credit"}},{"do":"expectActionOutcome","outcome":"refused"},{"do":"freshClient"},{"do":"signIn","name":"credit-owner-753"},{"do":"click","unlessVisible":"credit-panel"},{"attribute":"aria-busy","do":"expect","value":"false"},{"do":"expectNumber","equals":10}],"source":"scenarios/progression-store-credit.json","stableKey":"ecommerce.spec.store-credit.production-753.753a","statedBy":null,"withheld":null},{"category":"production","checkGroupId":"production-754","criterionId":"754a","description":"Concurrent checkout consumes one cart and one credit allocation","featureId":754,"featureName":"Concurrent checkout consumes one cart and one credit allocation","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.store-credit","points":2,"provenBy":null,"requiresFeatures":["ecommerce.feature.store-credit"],"role":"guarantee","semantics":[{"action":"checkoutCredit","do":"callConcurrently","namedAction":{"args":[],"id":"checkoutCredit","method":"POST","path":"/api/checkout/credit","reducer":"checkout_credit"}},{"do":"expectCallOutcomes"},{"do":"freshClient"},{"do":"signIn","name":"credit-owner-754"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"contains":"Desk Lamp","do":"expectElementCount","equals":1},{"do":"expectNumber","equals":10},{"do":"expectNumber","equals":32},{"do":"expectNumber","equals":42},{"do":"click","unlessVisible":"credit-panel"},{"attribute":"aria-busy","do":"expect","value":"false"},{"do":"expectNumber","equals":0}],"source":"scenarios/progression-store-credit.json","stableKey":"ecommerce.spec.store-credit.production-754.754a","statedBy":null,"withheld":null},{"category":"production","checkGroupId":"production-755","criterionId":"755a","description":"Issued credit survives a backend restart","featureId":755,"featureName":"Issued credit survives a backend restart","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.store-credit","points":2,"provenBy":null,"requiresFeatures":["ecommerce.feature.store-credit"],"role":"guarantee","semantics":[{"do":"restartBackend"},{"do":"freshClient"},{"do":"signIn","name":"credit-owner-755"},{"do":"click","unlessVisible":"credit-panel"},{"attribute":"aria-busy","do":"expect","value":"false"},{"do":"expectNumber","equals":10}],"source":"scenarios/progression-store-credit.json","stableKey":"ecommerce.spec.store-credit.production-755.755a","statedBy":null,"withheld":null},{"category":"feature","checkGroupId":"subscriptions-760","criterionId":"760a","description":"A subscription creates exactly its requested deliveries and payments","featureId":760,"featureName":"A subscription creates exactly its requested deliveries and payments","note":null,"packId":"ecommerce.feature.subscriptions","points":2,"provenBy":null,"role":"feature","semantics":[{"do":"freshClient"},{"do":"signIn","name":"subscription-760"},{"do":"click","unlessVisible":"subscriptions-panel"},{"attribute":"aria-busy","do":"expect","value":"false"},{"do":"expect","value":"complete"},{"do":"expectElementCount","equals":2},{"do":"expectSequence","equals":["paid","paid"]},{"do":"expectNumber","equals":84},{"do":"dbExpectStock","equals":8,"item":"Desk Lamp"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click"},{"contains":"Desk Lamp","do":"expectElementCount","equals":2},{"do":"expectElementCount","equals":2}],"source":"scenarios/progression-subscriptions.json","stableKey":"ecommerce.feature.subscriptions.subscriptions-760.760a","statedBy":null,"withheld":null},{"category":"production","checkGroupId":"production-761","criterionId":"761a","description":"A pending subscription continues after backend restart without duplicate deliveries","featureId":761,"featureName":"A pending subscription continues after backend restart without duplicate deliveries","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.subscriptions","points":2,"provenBy":null,"requiresFeatures":["ecommerce.feature.subscriptions"],"role":"guarantee","semantics":[{"do":"restartBackend"},{"do":"freshClient"},{"do":"signIn","name":"subscription-761"},{"do":"click","unlessVisible":"subscriptions-panel"},{"attribute":"aria-busy","do":"expect","value":"false"},{"do":"expect","value":"complete"},{"do":"expectElementCount","equals":2},{"do":"expectSequence","equals":["paid","paid"]},{"do":"expectNumber","equals":84},{"do":"dbExpectStock","equals":8,"item":"Desk Lamp"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click"},{"contains":"Desk Lamp","do":"expectElementCount","equals":2},{"do":"expectElementCount","equals":2},{"do":"restartBackend"},{"do":"freshClient"},{"do":"signIn","name":"subscription-761"},{"do":"click","unlessVisible":"subscriptions-panel"},{"attribute":"aria-busy","do":"expect","value":"false"},{"do":"expect","value":"complete"},{"do":"expectElementCount","equals":2},{"do":"expectSequence","equals":["paid","paid"]},{"do":"expectNumber","equals":84},{"do":"dbExpectStock","equals":8,"item":"Desk Lamp"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click"},{"contains":"Desk Lamp","do":"expectElementCount","equals":2},{"do":"expectElementCount","equals":2}],"source":"scenarios/progression-subscriptions.json","stableKey":"ecommerce.spec.subscriptions.production-761.761a","statedBy":null,"withheld":null},{"category":"production","checkGroupId":"production-762","criterionId":"762a","description":"Another customer cannot cancel an active subscription","featureId":762,"featureName":"Another customer cannot cancel an active subscription","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.subscriptions","points":2,"provenBy":null,"requiresFeatures":["ecommerce.feature.subscriptions"],"role":"guarantee","semantics":[{"action":"cancelSubscription","do":"callAction","from":"owner","input":{"attribute":"data-action-input","testid":"subscription-cancel"},"namedAction":{"args":[0],"id":"cancelSubscription","method":"POST","params":[{"in":"path","name":"subscriptionId","placeholder":"{subscriptionId}","wireType":"u64"}],"path":"/api/subscriptions/{subscriptionId}/cancel","reducer":"cancel_subscription"}},{"do":"expectActionOutcome","outcome":"refused"},{"do":"expect","value":"active"},{"do":"click"},{"do":"freshClient"},{"do":"signIn","name":"subscription-762"},{"do":"click","unlessVisible":"subscriptions-panel"},{"attribute":"aria-busy","do":"expect","value":"false"},{"do":"expect","value":"cancelled"},{"as":"deliveries-at-cancel","count":true,"do":"recordNumber"},{"as":"stock-at-cancel","do":"dbRecordStock","item":"Desk Lamp"},{"do":"wait"},{"do":"expectElementCount","plus":0,"relativeTo":"deliveries-at-cancel"},{"do":"dbExpectStock","item":"Desk Lamp","plus":0,"relativeTo":"stock-at-cancel"}],"source":"scenarios/progression-subscriptions.json","stableKey":"ecommerce.spec.subscriptions.production-762.762a","statedBy":null,"withheld":null},{"category":"production","checkGroupId":"production-763","criterionId":"763a","description":"Pause survives a restart and resume completes the remaining deliveries","featureId":763,"featureName":"Pause survives a restart and resume completes the remaining deliveries","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.subscriptions","points":2,"provenBy":null,"requiresFeatures":["ecommerce.feature.subscriptions"],"role":"guarantee","semantics":[{"do":"click"},{"do":"expect","value":"paused"},{"do":"restartBackend"},{"do":"freshClient"},{"do":"signIn","name":"subscription-763"},{"do":"click","unlessVisible":"subscriptions-panel"},{"attribute":"aria-busy","do":"expect","value":"false"},{"do":"expect","value":"paused"},{"as":"deliveries-at-pause","count":true,"do":"recordNumber"},{"as":"stock-at-pause","do":"dbRecordStock","item":"Desk Lamp"},{"do":"wait"},{"do":"expectElementCount","plus":0,"relativeTo":"deliveries-at-pause"},{"do":"dbExpectStock","item":"Desk Lamp","plus":0,"relativeTo":"stock-at-pause"},{"do":"click"},{"do":"freshClient"},{"do":"signIn","name":"subscription-763"},{"do":"click","unlessVisible":"subscriptions-panel"},{"attribute":"aria-busy","do":"expect","value":"false"},{"do":"expect","value":"complete"},{"do":"expectElementCount","equals":2},{"do":"expectSequence","equals":["paid","paid"]},{"do":"expectNumber","equals":84},{"do":"dbExpectStock","equals":8,"item":"Desk Lamp"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click"},{"contains":"Desk Lamp","do":"expectElementCount","equals":2},{"do":"expectElementCount","equals":2}],"source":"scenarios/progression-subscriptions.json","stableKey":"ecommerce.spec.subscriptions.production-763.763a","statedBy":null,"withheld":null},{"category":"feature","checkGroupId":"support-history","criterionId":"612c","description":"the customer can view their support ticket history","featureId":612,"featureName":"Customer support history","note":null,"packId":"ecommerce.progression.support-history","points":1,"provenBy":null,"role":"feature","semantics":[{"do":"reload"},{"do":"ensureSignedIn","name":"support-owner"},{"do":"click","unlessVisible":"support-ticket"},{"contains":"Owner ticket {user:ticketmarker}","do":"expect"}],"source":"scenarios/progression-support-history.json","stableKey":"ecommerce.progression.support-history.support-history.612c","statedBy":"Signed-in customers can see their support ticket history.","withheld":null},{"category":"production","checkGroupId":"support-history-reload","criterionId":"612a","description":"support history survives reload and backend restart in a fresh browser","featureId":612,"featureName":"Customer support history","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.state-durability","points":2,"provenBy":null,"requiresFeatures":["ecommerce.progression.support-history"],"role":"guarantee","semantics":[{"do":"reload"},{"do":"ensureSignedIn","name":"support-owner"},{"do":"click"},{"contains":"Owner ticket {user:ticketmarker}","do":"expect"},{"do":"restartBackend"},{"do":"freshClient"},{"do":"signIn","name":"support-owner"},{"do":"click"},{"contains":"Owner ticket {user:ticketmarker}","do":"expect"}],"source":"scenarios/progression-support-history.json","stableKey":"ecommerce.spec.state-durability.support-history-reload.612a","statedBy":"A customer's support history persists.","withheld":null},{"category":"production","checkGroupId":"support-history-privacy","criterionId":"612b","description":"another customer neither sees nor receives the private ticket","featureId":612,"featureName":"Customer support history","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"provenBy":null,"requiresFeatures":["ecommerce.progression.support-history"],"role":"guarantee","semantics":[{"do":"reload"},{"do":"ensureSignedIn","name":"support-owner"},{"do":"click"},{"do":"fill","text":"owner@example.com"},{"do":"fill","text":"Private ticket {user:privateticketmarker}"},{"do":"fill","text":"Private account issue."},{"do":"click"},{"do":"expect","nonEmpty":true},{"do":"reload"},{"do":"ensureSignedIn","name":"support-owner"},{"do":"click"},{"contains":"Private ticket {user:privateticketmarker}","do":"expect"},{"contains":"Private ticket {user:privateticketmarker}","do":"expectReceived"},{"do":"reload"},{"do":"ensureSignedIn","name":"support-other"},{"do":"click"},{"absent":true,"contains":"Private ticket {user:privateticketmarker}","do":"expect"},{"contains":"Private ticket {user:privateticketmarker}","do":"expectNotReceived"}],"source":"scenarios/progression-support-history.json","stableKey":"ecommerce.spec.access-control.support-history-privacy.612b","statedBy":"Customers cannot see another customer's support tickets.","withheld":null},{"category":"production","checkGroupId":"support-history-logout","criterionId":"612d","description":"after logout the same browser storage no longer grants access to private support history","featureId":612,"featureName":"Customer support history","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"provenBy":null,"requiresFeatures":["ecommerce.progression.support-history"],"role":"guarantee","semantics":[{"do":"reload"},{"do":"ensureSignedIn","name":"support-owner"},{"do":"click"},{"do":"fill","text":"owner@example.com"},{"do":"fill","text":"Logout ticket {user:logoutticketmarker}"},{"do":"fill","text":"Private account issue."},{"do":"click"},{"do":"expect","nonEmpty":true},{"do":"reload"},{"do":"ensureSignedIn","name":"support-owner"},{"do":"click","unlessVisible":"support-ticket"},{"contains":"Logout ticket {user:logoutticketmarker}","do":"expect"},{"contains":"Logout ticket {user:logoutticketmarker}","do":"expectReceived"},{"do":"reload"},{"do":"ensureSignedIn","name":"support-owner"},{"do":"click","unlessVisible":"signout"},{"do":"click"},{"do":"waitUntilAbsent"},{"do":"freshClient","preserveStorage":true},{"absent":true,"do":"expect"},{"do":"click"},{"do":"expect"},{"absent":true,"contains":"Logout ticket {user:logoutticketmarker}","do":"expect"},{"contains":"Logout ticket {user:logoutticketmarker}","do":"expectNotReceived"}],"source":"scenarios/progression-support-history.json","stableKey":"ecommerce.spec.access-control.support-history-logout.612d","statedBy":"Signed-out visitors cannot access private support tickets.","withheld":null},{"category":"feature","checkGroupId":"support-intake","criterionId":"610a","description":"a visitor can submit a support ticket and receives a reference","featureId":610,"featureName":"Support intake","note":null,"packId":"ecommerce.progression.support-intake","points":2,"provenBy":null,"role":"feature","semantics":[{"do":"click"},{"do":"fill","text":"visitor@example.com"},{"do":"fill","text":"Damaged package"},{"do":"fill","text":"The package arrived damaged."},{"do":"click"},{"do":"expect","nonEmpty":true}],"source":"scenarios/progression-support-intake.json","stableKey":"ecommerce.progression.support-intake.support-intake.610a","statedBy":"Anyone can open a support ticket and receives a reference.","withheld":null},{"category":"production","checkGroupId":"support-refund-access","criterionId":"615c","description":"a customer cannot issue a refund or change its records","featureId":615,"featureName":"Support refund access","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":1,"provenBy":null,"requiresFeatures":["ecommerce.progression.support-refunds"],"role":"guarantee","semantics":[{"absent":true,"do":"expect"},{"action":"supportRefund","authentication":"actor","do":"callAction","from":"staff","input":{"attribute":"data-action-input","testid":"support-refund"},"namedAction":{"args":[0],"id":"supportRefund","method":"POST","params":[{"in":"path","name":"caseId","placeholder":"{caseId}","wireType":"u64"}],"path":"/api/support/cases/{caseId}/refund","reducer":"support_refund"}},{"do":"expectActionOutcome","outcome":"refused"},{"do":"reload"},{"do":"ensureSignedIn","name":"refund-access-owner"},{"do":"click","ifAvailable":true},{"do":"click","unlessVisible":"support-subject"},{"do":"expect","notContains":"resolved"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click"},{"do":"expect","value":"pending"},{"absent":true,"contains":"Keyboard","do":"expect"}],"source":"scenarios/progression-support-refunds-access.json","stableKey":"ecommerce.spec.access-control.support-refund-access.615c","statedBy":"Only authorized staff can refund an order from a support case.","withheld":null},{"category":"production","checkGroupId":"support-refund-accounting","criterionId":"615b","description":"the refund equals the paid total, cannot be applied twice, and leaves another order unrefunded","featureId":615,"featureName":"Support refund accounting","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.transactional-integrity","points":1,"provenBy":null,"requiresFeatures":["ecommerce.progression.support-refunds"],"role":"guarantee","semantics":[{"do":"click"},{"do":"reload"},{"do":"ensureSignedIn","name":"refund-accounting-owner"},{"do":"click","ifAvailable":true},{"do":"click","unlessVisible":"support-subject"},{"do":"expectNumber","plus":0,"relativeTo":"paid-total"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"do":"expectNumber","plus":0,"relativeTo":"paid-total"},{"contains":"Keyboard","do":"expectElementCount","equals":1},{"do":"replayAs","from":"staff","match":"refund","namedAction":{"args":[0],"id":"supportRefund","method":"POST","params":[{"in":"path","name":"caseId","placeholder":"{caseId}","wireType":"u64"}],"path":"/api/support/cases/{caseId}/refund","reducer":"support_refund"},"namedTarget":{"attribute":"data-entity-id","contains":"Accounting refund case","testid":"support-ticket","valueType":"string"}},{"do":"expectReplayCompleted"},{"do":"freshClient"},{"do":"signIn","name":"refund-accounting-owner"},{"do":"click"},{"do":"expectNumber","plus":0,"relativeTo":"paid-total"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"do":"expectNumber","plus":0,"relativeTo":"paid-total"},{"contains":"Keyboard","do":"expectElementCount","equals":1},{"do":"expectNumber","equals":0},{"contains":"Mouse","do":"expectElementCount","equals":0}],"source":"scenarios/progression-support-refunds-accounting.json","stableKey":"ecommerce.spec.transactional-integrity.support-refund-accounting.615b","statedBy":"The recorded refund equals the amount paid and is applied only once.","withheld":null},{"category":"feature","checkGroupId":"support-refunds-resolution","criterionId":"615a","description":"an authorized refund resolves the case and updates the order","featureId":615,"featureName":"Support refund resolution","note":null,"packId":"ecommerce.progression.support-refunds","points":2,"provenBy":null,"role":"feature","semantics":[{"do":"click"},{"contains":"resolved","do":"expect"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click"},{"contains":"refunded","do":"expect"}],"source":"scenarios/progression-support-refunds-resolution.json","stableKey":"ecommerce.progression.support-refunds.support-refunds-resolution.615a","statedBy":"Authorized staff can refund an order from its support case.","withheld":null},{"category":"production","checkGroupId":"return-refund-interaction","criterionId":"757a","description":"a support refund followed by physical return restores each warehouse once and refunds only the price paid","featureId":757,"featureName":"Return and support refund accounting","note":null,"packId":"ecommerce.feature.split-tender-refunds","points":2,"provenBy":null,"requiresFeatures":["ecommerce.l3.order-returns-features","ecommerce.progression.fulfilment-queue","ecommerce.progression.support-refunds"],"role":"feature","semantics":[{"do":"reload"},{"do":"ensureSignedIn","name":"return-refund-owner"},{"do":"click","ifAvailable":true},{"as":"757atotal","do":"dbRecordStock","item":"Keyboard"},{"as":"757aEast","do":"dbRecordStock","item":"Keyboard","warehouse":"East"},{"as":"757aWest","do":"dbRecordStock","item":"Keyboard","warehouse":"West"},{"as":"757arevenue","do":"recordNumber"},{"do":"click"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"do":"expect","ignoreCase":true,"value":"pending"},{"as":"757apaid","do":"recordNumber"},{"action":"ship","do":"callAction","from":"owner","input":{"attribute":"data-ship-input","contains":"Keyboard","testid":"order-item"},"namedAction":{"args":[0],"id":"ship","params":[{"in":"body","name":"orderId","wireType":"u64"}],"path":"/api/fulfilment/ship","reducer":"ship_order"}},{"do":"expectActionOutcome","outcome":"accepted"},{"do":"expect","ignoreCase":true,"value":"shipped"},{"do":"dbExpectStock","item":"Keyboard","plus":-1,"relativeTo":"757atotal"},{"do":"reload"},{"do":"ensureSignedIn","name":"return-refund-owner"},{"do":"click"},{"do":"fill","text":"Return refund 757a"},{"do":"fill","text":"Please refund this order."},{"do":"click"},{"contains":"Return refund 757a","do":"expect"},{"do":"click"},{"do":"click"},{"do":"expect"},{"action":"supportRefund","do":"callAction","from":"owner","input":{"attribute":"data-refund-input","contains":"Return refund 757a","testid":"support-ticket"},"namedAction":{"args":[0],"id":"supportRefund","method":"POST","params":[{"in":"path","name":"caseId","placeholder":"{caseId}","wireType":"u64"}],"path":"/api/support/cases/{caseId}/refund","reducer":"support_refund"}},{"do":"expectActionOutcome","outcome":"accepted"},{"do":"dbExpectStock","item":"Keyboard","plus":-1,"relativeTo":"757atotal"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"do":"click"},{"contains":"Keyboard","containsText":"returned","do":"expect","ignoreCase":true},{"do":"freshClient"},{"do":"signIn","name":"return-refund-owner"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click"},{"contains":"Keyboard","containsText":"returned","do":"expect","ignoreCase":true},{"do":"expectNumber","plus":0,"relativeTo":"757apaid"},{"do":"dbExpectStock","item":"Keyboard","plus":0,"relativeTo":"757aEast","warehouse":"East"},{"do":"dbExpectStock","item":"Keyboard","plus":0,"relativeTo":"757aWest","warehouse":"West"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","unlessVisible":"admin-revenue"},{"do":"expectNumber","plus":0,"relativeTo":"757arevenue"}],"source":"scenarios/progression-support-return-interaction.json","stableKey":"ecommerce.feature.split-tender-refunds.return-refund-interaction.757a","statedBy":null,"withheld":null},{"category":"production","checkGroupId":"return-refund-interaction","criterionId":"757b","description":"a physical return followed by support refund restores each warehouse once and refunds only the price paid","featureId":757,"featureName":"Return and support refund accounting","note":null,"packId":"ecommerce.feature.split-tender-refunds","points":2,"provenBy":null,"requiresFeatures":["ecommerce.l3.order-returns-features","ecommerce.progression.fulfilment-queue","ecommerce.progression.support-refunds"],"role":"feature","semantics":[{"do":"reload"},{"do":"ensureSignedIn","name":"return-refund-owner"},{"do":"click","ifAvailable":true},{"as":"757btotal","do":"dbRecordStock","item":"Desk Lamp"},{"as":"757bEast","do":"dbRecordStock","item":"Desk Lamp","warehouse":"East"},{"as":"757bWest","do":"dbRecordStock","item":"Desk Lamp","warehouse":"West"},{"as":"757brevenue","do":"recordNumber"},{"do":"click"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"do":"expect","ignoreCase":true,"value":"pending"},{"as":"757bpaid","do":"recordNumber"},{"action":"ship","do":"callAction","from":"owner","input":{"attribute":"data-ship-input","contains":"Desk Lamp","testid":"order-item"},"namedAction":{"args":[0],"id":"ship","params":[{"in":"body","name":"orderId","wireType":"u64"}],"path":"/api/fulfilment/ship","reducer":"ship_order"}},{"do":"expectActionOutcome","outcome":"accepted"},{"do":"expect","ignoreCase":true,"value":"shipped"},{"do":"dbExpectStock","item":"Desk Lamp","plus":-1,"relativeTo":"757btotal"},{"do":"reload"},{"do":"ensureSignedIn","name":"return-refund-owner"},{"do":"click"},{"do":"fill","text":"Return refund 757b"},{"do":"fill","text":"Please refund this order."},{"do":"click"},{"contains":"Return refund 757b","do":"expect"},{"do":"click"},{"do":"click"},{"do":"expect"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"do":"click"},{"contains":"Desk Lamp","containsText":"returned","do":"expect","ignoreCase":true},{"action":"supportRefund","do":"callAction","from":"owner","input":{"attribute":"data-refund-input","contains":"Return refund 757b","testid":"support-ticket"},"namedAction":{"args":[0],"id":"supportRefund","method":"POST","params":[{"in":"path","name":"caseId","placeholder":"{caseId}","wireType":"u64"}],"path":"/api/support/cases/{caseId}/refund","reducer":"support_refund"}},{"do":"expectActionOutcome","outcome":"accepted"},{"do":"freshClient"},{"do":"signIn","name":"return-refund-owner"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click"},{"contains":"Desk Lamp","containsText":"returned","do":"expect","ignoreCase":true},{"do":"expectNumber","plus":0,"relativeTo":"757bpaid"},{"do":"dbExpectStock","item":"Desk Lamp","plus":0,"relativeTo":"757bEast","warehouse":"East"},{"do":"dbExpectStock","item":"Desk Lamp","plus":0,"relativeTo":"757bWest","warehouse":"West"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","unlessVisible":"admin-revenue"},{"do":"expectNumber","plus":0,"relativeTo":"757brevenue"}],"source":"scenarios/progression-support-return-interaction.json","stableKey":"ecommerce.feature.split-tender-refunds.return-refund-interaction.757b","statedBy":null,"withheld":null},{"category":"feature","checkGroupId":"support-assignment","criterionId":"611a","description":"staff can assign a new ticket","featureId":611,"featureName":"Support triage","note":null,"packId":"ecommerce.progression.support-triage","points":1,"provenBy":null,"role":"feature","semantics":[{"do":"fill","text":"staff"},{"do":"click"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"do":"click","ifAvailable":true,"unlessVisible":"support-assignee"},{"do":"click","ifAvailable":true,"unlessVisible":"support-assignee"},{"do":"expect","value":"staff"}],"source":"scenarios/progression-support-triage.json","stableKey":"ecommerce.progression.support-triage.support-assignment.611a","statedBy":"Staff can assign support tickets.","withheld":null},{"category":"feature","checkGroupId":"support-priority","criterionId":"611b","description":"staff can set a ticket priority","featureId":611,"featureName":"Support triage","note":null,"packId":"ecommerce.progression.support-triage","points":1,"provenBy":null,"role":"feature","semantics":[{"do":"fill","text":"high"},{"do":"click"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"do":"click","ifAvailable":true,"unlessVisible":"support-assignee"},{"do":"click","ifAvailable":true,"unlessVisible":"support-assignee"},{"do":"expect","value":"high"}],"source":"scenarios/progression-support-triage.json","stableKey":"ecommerce.progression.support-triage.support-priority.611b","statedBy":"Staff can set support ticket priority.","withheld":null},{"category":"feature","checkGroupId":"support-status","criterionId":"611c","description":"staff can change a ticket status","featureId":611,"featureName":"Support triage","note":null,"packId":"ecommerce.progression.support-triage","points":1,"provenBy":null,"role":"feature","semantics":[{"do":"fill","text":"in progress"},{"do":"click"},{"contains":"in progress","do":"expect"}],"source":"scenarios/progression-support-triage.json","stableKey":"ecommerce.progression.support-triage.support-status.611c","statedBy":"Staff can change support ticket status.","withheld":null}],"schemaVersion":3,"task":{"baseMeaningSha256":null,"contracts":[{"id":"ecommerce.application-interface","owners":["recipe"],"text":"# Application interface\n\nUse each interface name below as an exact HTML attribute value. Use `id` for\na one-off element. Use `data-role` when the same interface can\nappear more than once. These attributes do not prescribe the layout, data\nmodel, libraries, or transport.\n\n\nFor error responses, use HTTP 401 or 403 for access errors and 400, 409, or 422 for input errors.\n\n\n\nReport reducer errors by failing the call.\n\n\nHuman-readable status text is case-insensitive. Machine identifiers and protocol values keep their specified spelling.\n"},{"id":"ecommerce.progression.staff-access-hooks","owners":["ecommerce.progression.staff-access"],"text":"## Staff access controls\n\nUse the existing account sign-in controls. Use `staff-link` for the staff area and `admin-link`\nfor the administrator area. Use `staff-area` for the staff tools, not for a loading or error message.\n\nUse these provided accounts:\n\n- staff: `staff` / `stackbench-staff-2026`\n- administrator: `admin` / `stackbench-admin-2026`\n- customer: `customer` / `stackbench-customer-2026`\n"},{"id":"ecommerce.progression.customer-profile-hooks","owners":["ecommerce.progression.customer-profile"],"text":"# Customer profile application interface\n\nUse `catalog-link` to return to the catalog. If a profile overlay blocks navigation,\nexpose `overlay-close` to dismiss it. Saving may leave the profile open.\n\nMake `profile-link` available from the catalog while signed in, without first opening another\narea. Use it to open the profile. Use `profile-name` and `profile-address` for the editable\nvalues. Use `profile-save` to save them. Use `profile-address-summary` to display\nthe saved address in the profile view.\n"},{"id":"ecommerce.progression.staff-role-hooks","owners":["ecommerce.progression.staff-roles"],"text":"# Staff role application interface\n\nPut role management in the administrator area opened by `admin-link`.\nUse `staff-role-row` for each staff account and set `data-account-id` to that account's server\nidentifier. Put `staff-role-select` and `staff-role-save` inside the row.\nAlso set the row's HTML `id` to `staff-role-account-` followed by\n`encodeURIComponent(username)`, using the exact account username without changing its case.\nFor example, username `staff` has row ID `staff-role-account-staff`. This identifies the\naccount independently of the role options or other text in the row.\n\nThe staff sign-in and staff-area controls come from the staff access feature.\n\nExpose the same role assignment used by `staff-role-save`.\n\n\nUse `PUT /api/staff/:id/role`, where `:id` is the account identifier from `data-account-id`.\nThe JSON body is `{ \"role\": \"\" }`.\n\n\n\nUse the `assign_staff_role` reducer with arguments in this order: `accountId: u64`,\n`role: string`. Render `data-account-id` as the decimal account identifier without precision loss.\n\n\n`staff-role-select` offers the roles `staff`, `inventory`, and `admin` as its option values.\n"},{"id":"ecommerce.progression.catalog-management-hooks","owners":["ecommerce.progression.catalog-management"],"text":"# Catalog management application interface\n\nUse `admin-link` to open the administrator area containing the product controls.\nUse `catalog-name`, `catalog-category`, `catalog-price`, and `catalog-variants` for the product\nvalues; `catalog-category` accepts a new category name as text, and `catalog-variants` accepts\ncomma-separated variant names. Use `catalog-save` to add the product. Use `item-variant` for each named variant shown\nto a visitor.\n"},{"id":"ecommerce.progression.payment-record-hooks","owners":["ecommerce.progression.payment-records"],"text":"# Payment record application interface\n\nUse `payment-record`, `payment-status`, and `payment-amount` inside the matching `order-item`.\n"},{"id":"ecommerce.progression.staff-activity-hooks","owners":["ecommerce.progression.staff-activity"],"text":"# Staff activity application interface\n\nUse `activity-link` to open staff activity history and `activity-entry` for each change. Inside\neach entry, use `activity-actor`, `activity-action`, `activity-subject`, and `activity-time`.\n"},{"id":"ecommerce.feature.catalog-items.hooks","owners":["ecommerce.feature.catalog-items"],"text":"# Catalog item application interface\n\n| Element ID | Required element |\n| --- | --- |\n| `item-list` | Contains the public catalog items. |\n| `item-card` | Shows one catalog item. |\n| `item-name` | Shows the item name inside its `item-card`; activating it opens `item-detail`. |\n| `item-price` | Shows the numeric item price inside its `item-card`. |\n| `item-stock` | Shows total stock inside its `item-card`. |\n| `item-detail` | Contains the selected item's details. |\n"},{"id":"ecommerce.feature.catalog-discovery.hooks","owners":["ecommerce.feature.catalog-discovery"],"text":"# Catalog discovery application interface\n\nNew catalog data starts with zero purchases. Do not seed sample orders or purchase counts.\nWhen adding this feature to an existing app, preserve purchases made through the app.\n\n| Element ID | Required element |\n| --- | --- |\n| `item-list` | Contains exactly the ten ranked storefront items. |\n| `item-card` | Shows one storefront or search result. |\n| `item-name` | Shows the item name inside its `item-card`. |\n| `search-input` | Searches the full catalog as the visitor types or when they press Enter; no separate control runs the search. |\n| `search-results` | Contains matching `item-card` results. |\n"},{"id":"ecommerce.l2.transfer-hooks","owners":["ecommerce.l2.stock-transfers-features"],"text":"# Stock transfer application interface\n\nPut `transfer-from`, `transfer-to`, `transfer-qty`, and `transfer-submit` inside the applicable\n`admin-item-row`. Use `warehouse-total` inside each `admin-warehouse-item` for its numeric stock\ntotal. Show `order-error` when a transfer is refused.\n\nPut `data-transfer-input` on each `admin-item-row`. Its value is a JSON object with exactly\n`itemId`, `fromWarehouseId`, and `toWarehouseId` for the currently selected source and destination.\nIdentifiers can be JSON numbers or strings.\n\n\nExpose `POST /api/admin/transfer`. The JSON body has `itemId`, `fromWarehouseId`,\n`toWarehouseId`, and `quantity`.\n\n\n\nExpose `admin_transfer_stock` with arguments in this order: `itemId: u64`,\n`fromWarehouseId: u64`, `toWarehouseId: u64`, `quantity`.\n\n"},{"id":"ecommerce.l2.price-hooks","owners":["ecommerce.l2.price-history-features"],"text":"# Price history application interface\n\nPut `price-input` and `price-submit` inside the applicable `admin-item-row`.\n\nPut a `data-price-input` attribute on each `admin-item-row`. Its value is a JSON object with\n`itemId` and numeric `price` from the current price input. Identifiers can be\nJSON numbers or strings.\n\n\nExpose `POST /api/admin/price`.\n\n\n\nExpose the `admin_change_price` reducer.\n\n\nUse the same action as the visible price control.\n"},{"id":"ecommerce.progression.price-history-order-hooks","owners":["ecommerce.progression.price-history-specifications"],"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.l2.price-history-features"],"text":"# Price history completed-order interface\n\nUse `orders-toggle`, `order-item`, and `order-total` to inspect the order created at checkout.\nUse `buy-now` inside an `item-card` to create a paid order before a price change.\n\n"},{"id":"ecommerce.progression.price-history-cart-hooks","owners":["ecommerce.progression.price-history-specifications"],"requiresFeatures":["ecommerce.feature.checkout","ecommerce.l2.price-history-features"],"text":"# Price history cart and checkout interface\n\nUse `add-to-cart` inside an `item-card`, `cart-toggle`, `cart-total`, and `checkout-submit`.\n"},{"id":"ecommerce.l2.inventory-dashboard-hooks","owners":["ecommerce.l2.inventory-dashboard"],"text":"# Inventory dashboard application interface\n\nUse `admin-link` to open the administrator area. If `low-stock-list` is on a separate screen\nwithin it, expose `low-stock-link` there to reach it. Use `low-stock-list` for items with 10 units\nor fewer and `low-stock-item` for each item. Use\n`buy-now` inside an `item-card` to create sales that change available stock.\n"},{"id":"ecommerce.l2.order-cancellation-hooks","owners":["ecommerce.l2.order-cancellation-features"],"text":"# Order cancellation application interface\n\nUse `order-status` for an order's state inside its `order-item`. Use `cancel-order` on a pending\norder. Use `catalog-link` to return to the catalog.\n`order-status` reads `pending` until the order ships, `shipped` once it has, and `cancelled`\nafter a cancellation. Later features may add further states after `shipped`.\n\nEach customer `order-item` must have `data-cancel-input` containing a JSON object with\nexactly `orderId`. Use the identifier representation required by the selected stack.\n\n\nUse `POST /api/orders/:id/cancel`.\n\n\n\nUse the `cancel_order` reducer.\n\n"},{"id":"ecommerce.l2.sales-dashboard-hooks","owners":["ecommerce.l2.sales-dashboard"],"text":"# Sales dashboard application interface\n\nOpen the administrator area with `admin-link`. If category totals are on a\nseparate tab or screen, expose `sales-link` there to open them. Omit this control\nwhen the totals are already shown.\n\nUse `category-row` for each product category, including a category with no sales yet, whose\nunits and revenue read 0. Use `category-units` and `category-revenue` inside each row. Use `recommended-list` for signed-out\nbest sellers and `recommended-item` for each item. Use `buy-now` inside an `item-card` to create\nsales activity for the dashboard. Each best seller contains its one-based `recommendation-rank`.\n"},{"id":"ecommerce.l2.recommendations-hooks","owners":["ecommerce.l2.recommendations"],"text":"# Recommendations application interface\n\nUse `recommended-list` for recommendations and `recommended-item` for each item in the list.\nUse `catalog-link` to open the catalog with this list visible.\n"},{"id":"ecommerce.feature.accounts.hooks","owners":["ecommerce.feature.accounts"],"text":"# Account application interface\n\nUse these exact `id` attributes on the corresponding visible controls. They do not prescribe UI\nstructure, data modeling, libraries, or implementation strategy.\n\nFrom the signed-out page, show the sign-up inputs, `signup-toggle`, or\n`signin-toggle`. If sign-up is inside the sign-in dialog, opening `signin-toggle`\nmust reveal the sign-up inputs or `signup-toggle`. That control must reveal the\nsign-up form. No other navigation is required to reach it.\nShow the sign-in inputs or `signin-toggle` on the signed-out page.\nWhile signed in, show `signout` directly or reveal it by clicking `current-user`.\nNo other navigation is required to reach sign-out.\n\n| Element ID | Observable element |\n|---|---|\n| `signup-username` | sign-up username input |\n| `signup-password` | sign-up password input |\n| `signup-submit` | sign-up submit control |\n| `signin-toggle` | control that reveals sign-in |\n| `signup-toggle` | reveals sign-up; available on the signed-out page or after opening `signin-toggle`; omit when sign-up inputs are already visible |\n| `signin-username` | sign-in username input |\n| `signin-password` | sign-in password input |\n| `signin-submit` | sign-in submit control |\n| `current-user` | Active account name, present only while signed in. Do not use this hook for a signed-out message. |\n| `signout` | sign-out control |\n| `auth-error` | visible account error |\n\nAccept any username of up to 48 characters made of letters, digits, and hyphens, and any\npassword of up to 64 characters.\n\nExpose the same account writes used by the UI.\n\nFor bearer-token authentication, expose `window.getSessionToken()` as a synchronous\nfunction that returns the current session's existing token, or `null` when signed out.\nThis hook does not prescribe credential storage. Return the caller's real credential;\ndo not create a separate identity.\n\n\nUse `POST /api/auth/signup` and `POST /api/auth/signin`. Both accept JSON with\n`username` and `password` fields.\n\n\n\nUse the `signUp` and `signIn` reducers. Both take `username` and `password`, in that order.\n\n"},{"id":"ecommerce.feature.purchasing.hooks","owners":["ecommerce.feature.purchasing"],"text":"# Purchasing application interface\n\nUse `catalog-link` to return to the catalog. Use `buy-now` inside an `item-card` to buy one unit. Use `orders-toggle` to open order history.\nIf an overlay blocks catalog navigation, expose a visible `overlay-close` control\nthat dismisses it before `catalog-link` is used. Screens without a blocking\noverlay need no such control. Dialogs, panels, and ordinary page layouts are all allowed.\nUse `order-item` for each order, containing the names of its purchased items. Inside that\n`order-item`, use `order-total` for its numeric total and `order-status` for its current state. Show `out-of-stock` inside an `item-card` once that item's stock reaches zero.\nUse `buy-error` for a failed purchase.\n\nPut `data-buy-input` on each `item-card`. Its value is a JSON object containing that item's\nserver identifier, for example `{\"itemId\":42}`. The identifier may be a JSON number or string.\nUse the same identifier for the visible buy action.\n\nExpose the same purchase used by `buy-now`.\n\n\nUse `POST /api/items/:id/buy`, where `:id` is the item identifier.\n\n\n\nUse the `buy_now` reducer with the item identifier.\n\n"},{"id":"ecommerce.feature.cart.hooks","owners":["ecommerce.feature.cart"],"text":"# Cart application interface\n\nUse `catalog-link` to return to the catalog. Use `add-to-cart` inside an `item-card` to add one unit. Use `cart-toggle` to open the cart.\nIf an overlay blocks catalog navigation, expose a visible `overlay-close` control\nthat dismisses it before `catalog-link` is used. Screens without a blocking\noverlay need no such control. Dialogs, panels, and ordinary page layouts are all allowed.\nUse `cart-count` for the total units, `cart-item` for each line, `cart-quantity` for its\nquantity, and `cart-total` for the numeric total. Use `cart-remove` to remove a line and\n`empty-cart` for an empty cart. Keep `cart-count` visible, showing 0, while the cart is empty.\n\nPut `data-buy-input` on each `item-card`. Its value is a JSON object containing that item's\nserver identifier, for example `{\"itemId\":42}`. Put `data-cart-input` on each `cart-item`.\nIts value contains the item identifier, for example `{\"itemId\":42}`. The identifier may be a\nJSON number or string.\n\nExpose the same add and quantity-update operations used by the cart controls.\n\n\nUse `POST /api/cart`. Put `itemId` in the JSON body.\nUse `PATCH /api/cart/:itemId`. Put `quantity` in the JSON body.\n\n\n\nUse the `add_to_cart` reducer with the item identifier.\nUse the `update_cart_quantity` reducer with the item identifier and quantity.\n\n\nUse `checkout-submit` to check out. Use `orders-toggle` to open order history and `order-item`\nfor each order created by checkout.\n"},{"id":"ecommerce.feature.checkout.hooks","owners":["ecommerce.feature.checkout"],"text":"# Checkout application interface\n\nUse `checkout-submit` to check out and `buy-error` for a failed checkout. Use `orders-toggle`\nto open order history and `order-item` for each order created by checkout.\n\nExpose the same checkout used by `checkout-submit`.\n\n\nUse `POST /api/checkout`.\n\n\n\nUse the `checkout` reducer.\n\n"},{"id":"ecommerce.orders.data","owners":["ecommerce.feature.checkout","ecommerce.feature.purchasing"],"text":"# Order data interface\n\nExpose the following data through the database's native read tools. These names\ndescribe a read interface; tables, collections, or database-native views over the\napplication's current records are allowed. Do not maintain separate copies for\nthis interface. Extra columns are allowed.\n\n- `item(id, name, price)` identifies catalog items and their current prices. These are the same items shown in the catalog.\n- `order_account(id, username)` identifies customer accounts. Do not include passwords or tokens in this interface.\n- `order_header(id, account_id, total, refunded, status)` contains every order from direct purchase or checkout, including cancelled orders. `total` is the amount booked for the order. `refunded` is the amount refunded so far, initially zero.\n- `order_line(id, order_id, item_id, quantity, unit_price)` contains each order's purchased lines and their booked unit prices.\n- When carts are available, `order_cart(account_id, item_id, quantity)` contains their current lines. An empty cart has no lines.\n- When carts and warehouse stock are available, `order_reservation(account_id, item_id, warehouse_id, quantity)` contains any stock held for those carts and already deducted from available `stock.quantity`. If the app does not hold stock for carts, this read interface is empty. This does not require adding stock reservations to the app.\n- When warehouse stock is available, `order_allocation(order_line_id, warehouse_id, quantity)` contains the original warehouse quantities used for each order line. Keep these quantities available after cancellation.\n\nEach `id` is a nonempty string or an exact nonnegative integer. Related identifiers\nrefer to that same `id`; a document may use `_id` when it has no `id`. Item and warehouse\nidentifiers match the existing `item` and `warehouse` data interfaces and the visible\napplication actions. Quantities are whole numbers. Money fields use the same currency\nunits as displayed prices, with at most two decimal places. Status uses the states in\nthe order interface.\n\nThe names and fields above must remain readable by the supplied database credentials\nas features are added. Customer screens and writes must use the same underlying records.\nThis does not require making customer data available to unauthenticated app users.\n"},{"id":"ecommerce.feature.reviews.hooks","owners":["ecommerce.feature.reviews"],"text":"# Review application interface\n\nOn item details, show the review form for eligible customers or expose\n`review-toggle` to open it. Omit this control when the form is already shown.\n\nUse `review-rating` on an input or select with values 1 through 5, `review-input` for the comment, and\n`review-submit` to submit it. Put the item's server identifier in\n`data-review-item-id` on `review-submit`. Use `review-average` for the numeric average,\n`review-item` for each visible review, and `review-error` for a failed submission.\n\nExpose the same review operation used by `review-submit`.\n\n\nUse `POST /api/items/:id/reviews`, where `:id` is the item identifier. Send `rating` and\n`comment` in the request body.\n\n\n\nUse the `submit_review` reducer with the item identifier, rating, and comment.\n\n"},{"id":"ecommerce.feature.warehouse-admin.hooks","owners":["ecommerce.feature.warehouse-admin"],"text":"# Warehouse administration application interface\n\nUse `admin-link` to open `admin-panel`. Use `admin-item-row` for each item and `admin-stock` for\nits numeric total stock. Use `admin-warehouse-item` for each warehouse. Use `admin-location-row`\nfor every item in every warehouse, including zero quantities; the row shows the item name and\nthe warehouse name, with\n`admin-location-qty` for its quantity. Use\n`restock-input` and `restock-submit` inside that row. Use `admin-revenue` for numeric total\nrevenue.\n\nKeep all item, warehouse, and holding rows available in the open admin panel, without pagination.\n\nPut a `data-restock-input` attribute on each `admin-location-row`. Its value is a JSON object\nwith exactly `itemId`, `warehouseId`, and a valid one-unit `quantity`. Identifiers can be JSON numbers or\nstrings.\n\nUse the same restock action as the visible control.\n\n## Stock data interface\n\nExpose singular tables `item(id, name, price)`, `warehouse(id, name)`, and\n`stock(item_id, warehouse_id, quantity)` for direct database access.\n`stock.item_id` and `stock.warehouse_id` reference `item.id` and `warehouse.id`; in a document\nstore they hold the referenced document's `id` value, or its `_id` when it has no `id`. Keep\nthese tables readable and writable with the database's own tools.\n\n\nExpose `POST /api/admin/restock`. The JSON body has the same fields as `data-restock-input`.\n\n\n\nExpose `admin_restock` with arguments in this order: `itemId: u64`, `warehouseId: u64`,\n`quantity`.\n\n"},{"id":"ecommerce.progression.support-history-hooks","owners":["ecommerce.progression.support-history"],"text":"## Customer support history controls\n\n`support-link` opens support. Use `support-ticket` for each ticket in the history, showing\nits subject. The intake form stays reachable from the same control.\n"},{"id":"ecommerce.progression.support-intake-hooks","owners":["ecommerce.progression.support-intake"],"text":"## Support intake controls\n\nUse `support-link` to open support. Use `support-email`, `support-subject`, and\n`support-message` for the ticket fields. Use `support-submit` to submit the ticket and\n`support-reference` to show its reference.\n"},{"id":"ecommerce.progression.support-triage-hooks","owners":["ecommerce.progression.support-triage"],"text":"## Support triage controls\n\nOpen the staff area with `staff-link`. If its ticket queue is on a separate tab or\nscreen, expose `support-queue-link` there to open it. Omit this control when the\neditable ticket controls are already shown.\n\nUse `support-ticket` for each ticket in the staff view. Within a ticket, use\n`support-assignee`, `support-priority`, and `support-status-input` for the editable fields.\nUse `support-update` to apply the changes. Use `support-status` to show the current status.\n`support-assignee` takes the assignee's username; if it is a select, its option values are the\nusernames. `support-priority` offers `low`, `normal`, and `high` as its option values.\n\n`support-status-input` offers the statuses `open`, `in progress`, and `resolved` as its option\nvalues; `support-status` shows the one chosen.\n"},{"id":"ecommerce.progression.fulfilment-queue-hooks","owners":["ecommerce.progression.fulfilment-queue"],"text":"# Fulfilment application interface\n\n| Element ID | Required element |\n| --- | --- |\n| `staff-link` | Opens the fulfilment area. |\n| `fulfilment-panel` | Contains fulfilment tools, including an empty queue; not a loading or error message. |\n| `queue-depth` | Shows the number of pending orders. |\n| `queue-item` | Shows one pending order and names its items. |\n| `queue-warehouse` | Shows the selected warehouse inside its `queue-item`. |\n| `ship-submit` | Marks the order in its `queue-item` as shipped. |\n\nOn `fulfilment-panel`, expose `data-submit-state` for the latest shipping submission:\n`idle` initially, `pending` immediately when submitted, `succeeded` only after the server\nconfirms success, or `failed` after rejection or transport failure. Keep the terminal state\non the panel when the shipped row disappears. A new submission must replace the old state.\n\n`order-status` reads `pending` until the order ships, `shipped` once it has, and `cancelled`\nafter a cancellation. Later features may add further states after `shipped`.\n\nEach customer `order-item` must have `data-ship-input` containing a JSON object with\nexactly `orderId`.\n\nUse the identifier representation required by the selected stack.\n\n\nUse `POST /api/fulfilment/ship` with `{ \"orderId\": ... }`.\n\n\n\nUse the `ship_order` reducer.\n\n"},{"id":"ecommerce.progression.promotion-rules-hooks","owners":["ecommerce.progression.promotion-rules"],"text":"# Promotion rule application interface\n\nUse `staff-link` to open the staff area. In that area, use `promotions-link` for promotion\nmanagement. Use `promotion-code`, `promotion-discount`,\n`promotion-start`, `promotion-end`, `promotion-limit`, and `promotion-submit` to create a rule.\nList rules as `promotion-item` elements and expose the saved values with the matching field IDs.\n\nExpose the same rule creation used by `promotion-submit`.\n\n\nUse `POST /api/promotions` with a JSON object containing `code` (string),\n`discountPercent` (number), `startMicros` and `endMicros` (integer numbers of microseconds\nsince the Unix epoch), and `usageLimit` (positive integer).\n\n\n\nUse the `create_promotion` reducer with arguments in this order: `code: string`,\n`discountPercent: f64`, `startMicros: i64`, `endMicros: i64`, `usageLimit: u32`.\nBoth time arguments are microseconds since the Unix epoch.\n\n\nOn a listed rule, `promotion-start` and `promotion-end` show the dates as entered, in ISO\n`YYYY-MM-DD` form.\n"},{"id":"ecommerce.progression.notification-preferences-hooks","owners":["ecommerce.progression.notification-preferences"],"text":"# Notification preference application interface\n\nSaving may leave settings open. Use `catalog-link` to return to the catalog. If\na settings overlay blocks navigation, expose `overlay-close` to dismiss it.\n\nMake `notification-settings` available from the catalog while signed in, without first opening another area. Use it to open the settings. Use `notification-order` and\n`notification-stock` for the choices, and `notification-save` to save them. Each choice exposes\nits current state in `data-state` as `on` or `off`.\nBoth choices start `off` for a new account. Activating `notification-order` or\n`notification-stock` switches it between `on` and `off`.\n"},{"id":"ecommerce.l3.reservation-hooks","owners":["ecommerce.l3.reservations-features"],"text":"# Reservation application interface\n\nUse `cart-reservation-timer` inside a `cart-item` for the remaining reservation time in seconds.\nUse `cart-item-expired` inside an expired cart line and `cart-expired-notice` after cart\nexpiration.\n"},{"id":"ecommerce.progression.managed-support-hooks","owners":["ecommerce.progression.managed-support"],"text":"# Managed support application interface\n\n## Managed support controls\n\nUse `support-ticket` for each case and set `data-entity-id` to that case's server identifier.\nWithin a case, use `support-status` for the current status, `support-reply` for the reply field,\n`support-reply-submit` to send a reply, and `support-reply-item` for each reply.\n\nExpose the same reply operation used by `support-reply-submit`.\n\n\nUse `POST /api/support/:id/replies`, where `:id` is the case identifier from `data-entity-id`.\nThe JSON body is `{ \"body\": \"\" }`.\n\n\n\nUse the `reply_support` reducer with arguments in this order: `ticketId: u64`, `body: string`.\nRender `data-entity-id` as the decimal case identifier without precision loss.\n\n"},{"id":"ecommerce.l3.scheduled-restock-hooks","owners":["ecommerce.l3.scheduled-restocks-features"],"text":"# Scheduled restock application interface\n\nUse `admin-link` to open the administrator area. If these controls are on a separate screen within\nit, expose `restocks-link` there to reach them. Use `schedule-restock-item`, `schedule-restock-warehouse`, `schedule-restock-qty`, and\n`schedule-restock-delay` for the inputs. Use `schedule-restock-submit` to schedule the restock.\nSet its `data-action-input` to a JSON object with exactly `item`, `warehouse`, `quantity`, and\n`delaySeconds`. `item` and `warehouse` are their names as strings; `quantity` and\n`delaySeconds` are JSON integers. Use `pending-restock-item` for each pending row and set its\n`data-entity-id` to the restock's server identifier, written as a decimal number.\nEach row contains the item name and sets `data-quantity` to its integer quantity. Use\n`pending-restock-remaining` for its remaining seconds, `pending-restock-cancel` to cancel it,\nand `stock-ledger-entry` for a completed stock movement.\n\n\nExpose `POST /api/admin/scheduled-restocks` and `DELETE /api/admin/scheduled-restocks/:id`.\nThe POST body has the same fields as `data-action-input`.\n\n\n\nExpose `schedule_restock` with arguments in this order: `item: string`, `warehouse: string`,\n`quantity: u32`, `delaySeconds: u32`; and `cancel_scheduled_restock` with `restockId: u64`.\n\n"},{"id":"ecommerce.l3.order-delivery-hooks","owners":["ecommerce.l3.order-delivery-features"],"text":"# Order delivery application interface\n\nUse `completed-order-item` for each completed order in the staff view. Use\n`completed-order-status` inside it for the current state. This extends the order lifecycle:\nafter `shipped`, `order-status` and `completed-order-status` read `delivered`.\n"},{"id":"ecommerce.l3.cart-expiration-hooks","owners":["ecommerce.l3.cart-expiration-features"],"text":"# Cart expiration application interface\n\nUse `cart-reservation-timer` inside a `cart-item` for the remaining reservation time in seconds.\nUse `cart-item-expired` inside an expired cart line and `cart-expired-notice` after cart\nexpiration.\n"},{"id":"ecommerce.progression.promotion-checkout-hooks","owners":["ecommerce.progression.promotion-checkout"],"text":"# Promotion checkout application interface\n\nUse `cart-promotion` for the code and `apply-promotion` to apply it. Use `promotion-error` when a\ncode is refused. Expose the saved discount as `order-discount` inside its `order-item`.\n"},{"id":"ecommerce.progression.stock-alert-hooks","owners":["ecommerce.progression.stock-alerts"],"text":"# Stock alert application interface\n\nUse `stock-alert` inside an unavailable `item-card` to request an alert. Use\n`notifications-toggle` to open notifications and `notification-item` for each alert.\nOn that `item-card`, expose `data-submit-state` for the latest stock-alert request:\n`idle` initially, `pending` immediately when submitted, `succeeded` only after the server\nconfirms success, or `failed` after rejection or transport failure. Keep the terminal state\nif the request button disappears. A new submission must replace the old state.\nUse `notifications-panel` for the opened notification view, including while its contents\nload. Set its `aria-busy` attribute to `false` only when the signed-in account's contents\nhave loaded successfully, including an empty list; keep it `true` while loading or after\na failed read. Its toggle may also close it.\nWithin a delivered stock alert, expose `stock-alert-delivery` containing the item's\ndisplayed name. A pending request must not expose `stock-alert-delivery`.\n\nUse `catalog-link` to return to the catalog. If an overlay blocks navigation,\nexpose a visible `overlay-close` control that dismisses it before navigation.\nScreens without a blocking overlay do not need this control.\n"},{"id":"ecommerce.l3.order-return-hooks","owners":["ecommerce.l3.order-returns-features"],"text":"# Order return application interface\n\nUse `return-item` inside an `order-item` for each item that can be returned. After a return,\nthe same `order-item` contains the word `returned`.\n\nEach ordinary item has an `order-line` containing its name, including while pending.\nSet `data-return-input` on that line to JSON with `orderId` and `itemId`, using the\nidentifiers accepted by the return action.\n\n\n`returnItem` is `POST /api/orders/{orderId}/items/{itemId}/return`.\n\n\n\n`returnItem` is `return_order_item(orderId, itemId)`.\n\n\nThe existing `orders-toggle`, `order-item`, `item-stock`, `admin-revenue`, and `catalog-link`\ninterfaces expose the order, stock, and accounting results.\n"},{"id":"ecommerce.progression.faceted-search-hooks","owners":["ecommerce.progression.faceted-search"],"text":"# Faceted search application interface\n\n| Element ID | Required element |\n| --- | --- |\n| `category-filter` | Sets the category filter; a text input, or a `select` whose option values are the category names. |\n| `minimum-price` | Sets the inclusive minimum price. |\n| `maximum-price` | Sets the inclusive maximum price. |\n| `in-stock-filter` | Toggles the in-stock-only filter, which starts off. |\n| `search-results` | Contains the filtered page; with no search text and no filter selected, the current page of the full catalog. |\n| `item-card` | Shows one result inside `search-results`. |\n| `search-next-page` | Opens the next page. |\n| `search-previous-page` | Opens the previous page. |\n\nIf a `filter-apply` control exists, activating it applies the filters; otherwise results update\nas each filter changes.\n\nSearch text or any active filter selects alphabetical ordering. With neither, use\npurchase ranking and break ties by item name. Clearing all search text and filters\nrestores purchase ranking. Both modes can use the same rendered list.\n"},{"id":"ecommerce.progression.order-support-hooks","owners":["ecommerce.progression.order-support"],"text":"# Order-linked support application interface\n\n## Order-linked support controls\n\nWithin a `support-ticket`, use `support-order-option` for each order that the customer can attach,\n`support-link-order` to attach the selected order, and `support-order` for the attached order. The\nlink action must expose its input in `data-action-input` for the named\n`linkSupportOrder` application action.\n\n\n`linkSupportOrder` is `POST /api/support/cases/{caseId}/order`.\n\n\n\n`linkSupportOrder` is the `link_support_order(caseId, orderId)` reducer.\n\n"},{"id":"ecommerce.progression.personalized-recommendation-hooks","owners":["ecommerce.progression.personalized-recommendations"],"text":"# Personalized recommendation application interface\n\nUse `recommendations` for the ordered recommendation list. Use `recommended-item` for each\nitem in that list. Each item contains its item name. Use `recommendation-rank` inside each item\nfor its one-based position in the list.\n"},{"id":"ecommerce.progression.promotion-reporting-hooks","owners":["ecommerce.progression.promotion-reporting"],"text":"# Promotion reporting application interface\n\nUse `promotions-link` to open the staff view. Use `promotion-report` for each promotion and\n`promotion-redemptions` and `promotion-revenue` for its totals.\n"},{"id":"ecommerce.feature.store-credit.interface","owners":["ecommerce.feature.store-credit"],"text":"# Store credit interface\n\nOpen customer credit with `credit-link`. The `credit-panel` exposes the signed-in account's `data-account-id` and `aria-busy=\"false\"` when loaded. Show `credit-balance` in major currency units and one `credit-entry` per movement.\n\nStaff use `credit-customer`, `credit-amount-input` (major units), `credit-reference-input`, and `credit-grant`. The grant control exposes `data-action-input` as JSON with `accountId`, `amountMinor`, and `reference`.\n\nUse `credit-checkout` in the cart. Each `order-item` shows `payment-credit-amount` and `payment-external-amount` in major units. Their sum is `payment-amount`.\n\n\n`grantCredit` is `POST /api/staff/credit` with `accountId`, `amountMinor`, and `reference`.\n`checkoutCredit` is `POST /api/checkout/credit` with no body fields.\n\n\n\n`grantCredit` is `grant_credit(accountId, amountMinor, reference)`.\n`checkoutCredit` is `checkout_credit()`.\n\n"},{"id":"ecommerce.feature.subscriptions.interface","owners":["ecommerce.feature.subscriptions"],"text":"# Subscription interface\n\nOpen with `subscriptions-link`. Use `subscription-item-input` (item name), `subscription-quantity-input`, `subscription-interval-input` (whole seconds, minimum 30), `subscription-deliveries-input` (1–12), and `subscription-create`.\n\nThe loaded `subscriptions-panel` has `aria-busy=\"false\"`. Each `subscription-row` includes the item name and `subscription-status`: `active`, `paused`, `cancelled`, or `complete`. Use `subscription-pause`, `subscription-resume`, and `subscription-cancel`; each exposes `data-action-input` with `subscriptionId`. Each processed slot has one `subscription-delivery` inside the row, with `subscription-delivery-status` (`paid` or `skipped`). `subscription-total` shows the sum of its recorded payments in major currency units. Ordinary orders and payment records include their item names.\n\n\n`pauseSubscription` is `POST /api/subscriptions/{subscriptionId}/pause`.\n`resumeSubscription` is `POST /api/subscriptions/{subscriptionId}/resume`.\n`cancelSubscription` is `POST /api/subscriptions/{subscriptionId}/cancel`.\n\n\n\n`pauseSubscription` is `pause_subscription(subscriptionId)`.\n`resumeSubscription` is `resume_subscription(subscriptionId)`.\n`cancelSubscription` is `cancel_subscription(subscriptionId)`.\n\n"},{"id":"ecommerce.progression.delivery-notification-hooks","owners":["ecommerce.progression.delivery-notifications"],"text":"# Delivery notification application interface\n\nUse `notifications-toggle` to open notifications. Use `notification-item` for each notification\nand `notification-unread-count` for the unread total.\n\nThe `notifications-panel` has `aria-busy=\"false\"` only when the signed-in account's\nnotifications have loaded. Keep the panel present when the list is empty.\n"},{"id":"ecommerce.progression.support-refund-hooks","owners":["ecommerce.progression.support-refunds"],"text":"# Support refund application interface\n\n## Support refund controls\n\nWithin a `support-ticket`, use `support-refund` for the refund action and\n`support-refund-total` for the recorded refund amount. The refund action must expose its input in\n`data-action-input` for the named `supportRefund` application action. The `support-ticket` also\nexposes the same JSON `{ \"caseId\": \"...\" }` in `data-refund-input` so the case remains addressable\nafter its refund button is disabled or removed. Within an `order-item`, use\n`order-refund-total` for the refunded amount and `refund-entry` for each refund record. Each\n`refund-entry` includes the order item name.\n\n\n`supportRefund` is `POST /api/support/cases/{caseId}/refund`.\n\n\n\n`supportRefund` is the `support_refund(caseId)` reducer.\n\n"},{"id":"ecommerce.progression.automatic-reorder-hooks","owners":["ecommerce.progression.automatic-reorder"],"text":"# Automatic reorder application interface\n\nUse these application interface names:\n\n- `reorder-link` opens the automatic reorder rules for warehouse staff.\n- `reorder-item`, `reorder-threshold`, and `reorder-quantity` identify the rule inputs.\n- `reorder-submit` saves the rule.\n- `reorder-rule-item` identifies each saved rule, sets `data-entity-id` to the rule's item\n identifier, and contains its item name, threshold, quantity, and current state.\n Set `data-threshold` and `data-quantity` to their integer values. Set\n `data-action-input` on `reorder-submit` to JSON with `itemId`, `threshold`, and `quantity`\n for the current form values.\n\nSaving a rule is the named `saveReorderRule` application action.\n\n\n`saveReorderRule` is `PUT /api/reorders/{itemId}` with `threshold` and `quantity` in the body.\n\n\n\n`saveReorderRule` is the `save_reorder_rule(itemId, threshold, quantity)` reducer.\n\n\nUse `buy-now` inside an `item-card` to create stock changes that evaluate a reorder rule.\n"},{"id":"ecommerce.progression.cart-recovery-hooks","owners":["ecommerce.progression.cart-recovery"],"text":"# Cart recovery application interface\n\nUse these application interface names:\n\n- `expired-cart` identifies the expired cart.\n- `restore-cart` restores that cart.\n- `cart-restore-warning` lists the names of items that could not be restored.\n\nThe existing `cart-item` control identifies each item restored to the active cart.\n"},{"id":"ecommerce.progression.recommendation-feedback-hooks","owners":["ecommerce.progression.recommendation-feedback"],"text":"# Recommendation feedback application interface\n\nUse `dismiss-recommendation` inside each `recommended-item`.\n"},{"id":"ecommerce.feature.split-tender-refunds.interface","owners":["ecommerce.feature.split-tender-refunds"],"text":"# Split refund interface\n\nReuse `support-refund` and its existing named action. Each `refund-entry` shows `refund-credit-amount` and `refund-external-amount` in major currency units. Show the restored credit in the existing credit balance and history.\n"},{"id":"ecommerce.interface.product-bundles","owners":["ecommerce.feature.product-bundles"],"text":"# Product bundle interface\n\nThe catalog has a `bundles-link`. The bundle panel contains `bundle-card` rows with\n`bundle-name`, numeric `bundle-price`, and `bundle-component` rows. Each component row has\n`bundle-component-name` and numeric `bundle-component-quantity`. Each component row also\nexposes its quantity in `data-quantity`.\n\nCatalog staff use `bundle-name-input`, `bundle-price-input` (currency units), and\n`bundle-components-input` (JSON array of `{ \"item\": \"product name\", \"quantity\": 1 }`),\nthen `bundle-save`. Saving an existing name edits that bundle. Each `bundle-card` exposes\n`data-bundle-input` as JSON `{ \"bundleId\": \"...\" }`.\nThe save button exposes `data-bundle-save-input` with `{ name, price, componentsJson }`\nfrom the current form values.\n\nUse the same application write for the visible form and this named action:\n\n\nSave a bundle with `POST /api/bundles` and `{ name, price, componentsJson }`.\n\n\n\nSave a bundle with `save_bundle(name: string, price: number, componentsJson: string)`.\n\n\nEach component uses an existing product's exact name. `componentsJson` contains the\ncomponent array as a JSON string.\n"},{"id":"ecommerce.interface.bundle-checkout","owners":["ecommerce.feature.bundle-checkout"],"text":"# Bundle checkout interface\n\nUse `bundle-add-to-cart` inside `bundle-card`. A bundle cart line uses the existing\n`cart-item`, `cart-reservation-timer`, and `cart-item-expired` interfaces, with\n`bundle-remove` to remove it. `checkout-submit` buys the cart through the existing checkout\naction. The existing `order-item` and `payment-amount` show the bundle name and price paid.\n\n\nAdd one bundle with `POST /api/cart/bundles` and `{ bundleId }`.\n\n\n\nAdd one bundle with `add_bundle_to_cart(bundleId: u64)`.\n\n\nUse the same application action as the visible control. The `data-bundle-input` attribute\nsupplies its bundle ID. The cart and order interfaces remain shared with individual products.\n"},{"id":"ecommerce.interface.bundle-returns","owners":["ecommerce.feature.bundle-returns"],"text":"# Bundle return interface\n\nUse `return-bundle` inside the existing `order-item`. Mark each returned bundle line\n`returned`. The order's `order-status` reads `returned` when all its lines have been\nreturned; otherwise keep its current fulfilment status. `bundle-refund-amount` shows\nthe refunded amount in currency units.\nEach bundle `order-item` exposes `data-bundle-return-input` as JSON `{ \"orderId\": \"...\" }`.\n\n\nReturn a whole bundle with `POST /api/bundle-orders/:orderId/return`.\n\n\n\nReturn a whole bundle with `return_bundle(orderId: u64)`.\n\n\nUse the same application action as the visible control.\n"}],"mode":"action","requirements":[{"id":"ecommerce.progression.fresh","owners":["recipe"],"text":"## New application\n\nBuild an ecommerce application from the product work below. Use `Storefront`\nas the visible page title. Use the application interface names where they are\nprovided. Start with no orders or purchase history.\n\n"},{"id":"ecommerce.progression.upgrade","owners":["recipe"],"text":"## Existing application\n\nAdd the current product work to the existing ecommerce application. Preserve its data;\ndo not add sample orders or purchase history while adding features.\n"},{"id":"ecommerce.l2.inventory-dashboard","owners":["ecommerce.l2.inventory-dashboard"],"text":"## Inventory dashboard\n\nGive administrators a low-stock view. It lists items with 10 units or fewer, most urgent first.\n"},{"id":"ecommerce.l2.sales-dashboard","owners":["ecommerce.l2.sales-dashboard"],"text":"## Sales dashboard\n\nGive customers and administrators sales views. Category totals show units sold and revenue for\neach category. Signed-out visitors see best sellers on the storefront.\n"},{"id":"ecommerce.l2.recommendations","owners":["ecommerce.l2.recommendations"],"text":"## Recommendations\n\nShow customers a recommended-for-you list on the catalog page. It recommends items from categories the customer has\nbought from and excludes items already in the cart.\n"},{"id":"ecommerce.feature.accounts.requirement","owners":["ecommerce.feature.accounts"],"text":"## Accounts\n\nVisitors can create an account with a username and password. Returning users can sign in with\nthose credentials, see which account is active, and sign out. Show a useful error for a taken\nusername or an incorrect password.\n"},{"id":"ecommerce.feature.catalog-items.requirement","owners":["ecommerce.feature.catalog-items"],"text":"## Catalog items\n\nShow public catalog items. Each item shows its name, price, and total stock.\n"},{"id":"ecommerce.feature.catalog-discovery.requirement","owners":["ecommerce.feature.catalog-discovery"],"text":"## Catalog discovery\n\nShow the ten most-purchased items. Break ties by item name. Search matches any part of\nan item name, without regard to case, across the full catalog.\n"},{"id":"ecommerce.feature.purchasing.requirement","owners":["ecommerce.feature.purchasing"],"text":"## Purchasing and orders\n\nA signed-in customer can buy one unit of an available item. The purchase reduces stock and\ncreates an order for that customer at the price paid. Their order history shows the newest\norders first, including items, quantities, prices, and totals.\n"},{"id":"ecommerce.feature.cart.requirement","owners":["ecommerce.feature.cart"],"text":"## Cart\n\nA signed-in customer has one cart. They can add an item, change its quantity, remove it, and\nsee the total. Adding the same item again increases the existing line quantity.\n"},{"id":"ecommerce.feature.checkout.requirement","owners":["ecommerce.feature.checkout"],"text":"## Checkout\n\nCheckout creates one order, reduces stock for every line, and empties the cart. Show an\nexplanation if checkout fails.\n"},{"id":"ecommerce.feature.reviews.requirement","owners":["ecommerce.feature.reviews"],"text":"## Reviews\n\nCustomers can rate items they purchased from one to five and add a comment. Show reviews\nand the average rating on the item detail.\n"},{"id":"ecommerce.feature.warehouse-admin.requirement","owners":["ecommerce.feature.warehouse-admin"],"text":"## Warehouse administration\n\nProvide an administration area that lists every item, both warehouses, and the quantity held in\neach warehouse. An administrator can add units to a selected item and warehouse. The area also\nshows total revenue across orders.\n"},{"id":"ecommerce.spec.access-control.purchasing","owners":["ecommerce.spec.access-control"],"requiresFeatures":["ecommerce.feature.purchasing"],"text":"## Access control: purchasing\n\nTreat identity as server-enforced authority, not UI decoration. Unauthenticated\ncallers cannot purchase, one account cannot place an order for another account,\nand order history is visible only to its owner. Knowing a username never grants\naccess to that account.\n\n"},{"id":"ecommerce.spec.access-control.warehouse-admin","owners":["ecommerce.spec.access-control"],"requiresFeatures":["ecommerce.feature.warehouse-admin"],"text":"## Access control: warehouse administration\n\nCustomer accounts cannot perform warehouse-administration writes. Enforce this\non the server even if the corresponding controls are hidden in the UI.\n\n"},{"id":"ecommerce.spec.access-control.reviews","owners":["ecommerce.spec.access-control"],"requiresFeatures":["ecommerce.feature.reviews"],"text":"## Access control: reviews\n\nOnly a customer who purchased an item may review it. Enforce this on the server\ninstead of relying on whether the review form is visible.\n\n"},{"id":"ecommerce.spec.access-control.cart","owners":["ecommerce.spec.access-control"],"requiresFeatures":["ecommerce.feature.cart"],"text":"## Access control: cart\n\nOne account cannot read or change another account's cart. Refuse a cart request\nwhose quantity is negative without changing state.\n\n"},{"id":"ecommerce.progression.staff-access","owners":["ecommerce.progression.staff-access"],"text":"## Staff access\n\nStaff and administrators can sign in and use staff areas.\n"},{"id":"ecommerce.spec.state-durability.accounts","owners":["ecommerce.spec.state-durability"],"requiresFeatures":["ecommerce.feature.accounts"],"text":"## State durability: accounts\n\nA signed-in session survives a page reload as the same account.\n\n"},{"id":"ecommerce.spec.state-durability.account-data","owners":["ecommerce.spec.state-durability"],"requiresFeatures":["ecommerce.feature.accounts","ecommerce.feature.cart"],"text":"## State durability: account data\n\nThe same account keeps its cart and orders across reload and connection loss.\nAfter reconnect it has current state without another sign-in. Restarting the\napplication must not duplicate starting data or reset state users changed.\n\n"},{"id":"ecommerce.spec.state-durability.checkout-crash","owners":["ecommerce.spec.state-durability"],"requiresFeatures":["ecommerce.feature.checkout"],"text":"After the application or database process restarts, an interrupted checkout leaves\neither its unchanged cart or one complete order with the cart cleared. A checkout\nreported as complete and the account's earlier orders remain recorded correctly.\nThe application can accept new checkouts after recovery.\n"},{"id":"ecommerce.progression.customer-profile","owners":["ecommerce.progression.customer-profile"],"text":"## Customer profile\n\nA signed-in customer can save and view their name and shipping address.\n"},{"id":"ecommerce.progression.support-intake","owners":["ecommerce.progression.support-intake"],"text":"## Support intake\n\nAnyone can open a support ticket with contact details, a subject, and a message. Return a\nreference that the visitor can use to identify the ticket.\n"},{"id":"ecommerce.spec.live-state.catalog-purchasing","owners":["ecommerce.spec.live-state"],"requiresFeatures":["ecommerce.feature.catalog-items","ecommerce.feature.purchasing"],"text":"## Live state: catalog and purchasing\n\nStock and best-seller ranking update every affected open storefront without a\nreload, including signed-out storefronts.\n\n"},{"id":"ecommerce.spec.live-state.cart","owners":["ecommerce.spec.live-state"],"requiresFeatures":["ecommerce.feature.cart"],"text":"## Live state: cart\n\nThe same account open in two clients sees one current cart; a change in either\nclient reaches the other without a reload.\n\n"},{"id":"ecommerce.spec.live-state.reviews","owners":["ecommerce.spec.live-state"],"requiresFeatures":["ecommerce.feature.reviews"],"text":"## Live state: reviews\n\nReviews and average ratings update affected open item views without a reload.\nA view opened while a review is submitted converges to the current review list.\n\n"},{"id":"ecommerce.spec.live-state.warehouse-admin","owners":["ecommerce.spec.live-state"],"requiresFeatures":["ecommerce.feature.catalog-items","ecommerce.feature.warehouse-admin"],"text":"## Live state: warehouse administration\n\nRestocking updates warehouse quantities, total item stock, and open storefronts\nwithout a reload.\n\n"},{"id":"ecommerce.progression.staff-roles","owners":["ecommerce.progression.staff-roles"],"text":"## Staff roles\n\nAn administrator can assign a role to an existing staff account. The `admin` role grants\nadministrator access. The `staff` and `inventory` roles grant staff access without\nadministrator access.\n"},{"id":"ecommerce.progression.catalog-management","owners":["ecommerce.progression.catalog-management"],"text":"## Catalog management\n\nAuthorized staff can add a product with named variants. The new product and its variants appear\nin the public catalog.\n"},{"id":"ecommerce.spec.concurrency-safety.purchasing","owners":["ecommerce.spec.concurrency-safety"],"requiresFeatures":["ecommerce.feature.purchasing"],"text":"## Concurrency safety: purchasing\n\nStock never becomes negative and only one customer can receive the last unit.\n\n"},{"id":"ecommerce.spec.concurrency-safety.restocking","owners":["ecommerce.spec.concurrency-safety"],"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.warehouse-admin"],"text":"## Concurrency safety: restocking\n\nConcurrent restocks and purchases preserve every accepted stock change.\n\n"},{"id":"ecommerce.spec.concurrency-safety.checkout","owners":["ecommerce.spec.concurrency-safety"],"requiresFeatures":["ecommerce.feature.checkout"],"text":"## Concurrency safety: checkout\n\nRepeating or racing checkout for the same cart creates only one order.\n\n"},{"id":"ecommerce.progression.payment-records","owners":["ecommerce.progression.payment-records"],"text":"## Payment records\n\nShow the payment status and amount paid on each order.\n"},{"id":"ecommerce.progression.staff-activity","owners":["ecommerce.progression.staff-activity"],"text":"## Staff activity history\n\nStaff can inspect a history of administrative changes. Each entry shows the staff member,\naction, subject, and time.\n"},{"id":"ecommerce.spec.transactional-integrity.reviews","owners":["ecommerce.spec.transactional-integrity"],"requiresFeatures":["ecommerce.feature.reviews"],"text":"## Transactional integrity: reviews\n\nA customer has at most one review per item. A later submission must not create\na duplicate; it may update the existing review or be refused.\n\n"},{"id":"ecommerce.spec.transactional-integrity.purchasing","owners":["ecommerce.spec.transactional-integrity"],"requiresFeatures":["ecommerce.feature.purchasing"],"text":"## Transactional integrity: purchasing\n\nThe server controls prices and order attribution rather than trusting client\nvalues. Historical order prices do not change.\n\n"},{"id":"ecommerce.spec.transactional-integrity.warehouse-accounting","owners":["ecommerce.spec.transactional-integrity"],"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.warehouse-admin"],"text":"## Transactional integrity: warehouse accounting\n\nEvery stock reduction caused by a sale has its matching order, revenue equals\nthe orders' recorded totals, and fresh clients agree with those results.\n\n"},{"id":"ecommerce.spec.external-data-sync.requirement","owners":["ecommerce.spec.external-data-sync"],"requiresFeatures":["ecommerce.feature.warehouse-admin"],"text":"## External data synchronization\n\nOther systems may write stock directly without calling the application. Open\npages and newly loaded pages must converge to a direct stock correction,\nincluding a correction made while the application server is down.\n"},{"id":"ecommerce.progression.fulfilment-queue","owners":["ecommerce.progression.fulfilment-queue"],"text":"# Fulfilment operations\n\nAdd a fulfilment area for staff and administrators. Show pending orders, their items, and the\nwarehouse that will ship them. Staff and administrators can mark an order as shipped. Show the\nnew status in the fulfilment area and the customer's order history.\n"},{"id":"ecommerce.l2.stock-transfer","owners":["ecommerce.l2.stock-transfers-features"],"text":"## Stock transfers\n\nAn administrator can move units of an item from one warehouse to another.\n"},{"id":"ecommerce.l2.order-cancellation","owners":["ecommerce.l2.order-cancellation-features"],"text":"## Order cancellation\n\nA customer can cancel an order before it ships. Refund the purchase, return its stock to\nthe supplying warehouse, and show its cancelled status in order history.\n"},{"id":"ecommerce.l2.price-history","owners":["ecommerce.l2.price-history-features"],"text":"## Price history\n\nAn administrator can change an item's price. Show the price in the public catalog.\n"},{"id":"ecommerce.progression.price-history-orders","owners":["ecommerce.progression.price-history-specifications"],"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.l2.price-history-features"],"text":"## Price history: completed orders\n\nCompleted orders keep the price paid at checkout. A later price change does not alter a receipt\nor revenue already recorded.\n\n"},{"id":"ecommerce.progression.price-history-cart-checkout","owners":["ecommerce.progression.price-history-specifications"],"requiresFeatures":["ecommerce.feature.checkout","ecommerce.l2.price-history-features"],"text":"## Price history: cart and checkout\n\nEvery open cart shows the new price without a reload. Checkout uses the current price.\n"},{"id":"ecommerce.progression.cancellation-queue","owners":["ecommerce.progression.cancellation-queue-specifications"],"requiresFeatures":["ecommerce.l2.order-cancellation-features","ecommerce.progression.fulfilment-queue"],"text":"## Fulfilment queue integration\n\nWhen fulfilment is available, cancelling a pending order also removes it from the fulfilment\nqueue.\n"},{"id":"ecommerce.progression.cancellation-accounting","owners":["ecommerce.progression.cancellation-accounting-specifications"],"requiresFeatures":["ecommerce.l2.order-cancellation-features"],"text":"## Cancellation accounting\n\nRevenue equals the sum of orders that remain paid. Cancellation removes the cancelled amount.\n\n"},{"id":"ecommerce.progression.support-triage","owners":["ecommerce.progression.support-triage"],"text":"## Support triage\n\nStaff can view new support tickets, assign a ticket, set its priority, and change its status.\n"},{"id":"ecommerce.progression.price-accounting","owners":["ecommerce.progression.price-accounting-specifications"],"requiresFeatures":["ecommerce.l2.price-history-features"],"text":"## Price accounting\n\nLater catalog price changes do not change the amount recorded on an existing order.\n"},{"id":"ecommerce.progression.support-history","owners":["ecommerce.progression.support-history"],"text":"## Customer support history\n\nSigned-in customers can see their support ticket history.\n"},{"id":"ecommerce.progression.promotion-rules","owners":["ecommerce.progression.promotion-rules"],"text":"## Promotion rules\n\nStaff can create promotion codes with a percentage discount, a start date, an end date, and a\nredemption limit.\n"},{"id":"ecommerce.progression.notification-preferences","owners":["ecommerce.progression.notification-preferences"],"text":"## Notification preferences\n\nSigned-in customers can turn order and stock notifications on or off.\n"},{"id":"ecommerce.progression.transfer-authorization","owners":["ecommerce.progression.operations-access-specifications"],"requiresFeatures":["ecommerce.l2.stock-transfers-features"],"text":"## Transfer authorization\n\nThe server allows only staff and administrators to transfer warehouse stock.\n"},{"id":"ecommerce.progression.price-authorization","owners":["ecommerce.progression.operations-access-specifications"],"requiresFeatures":["ecommerce.l2.price-history-features"],"text":"## Price authorization\n\nThe server allows only administrators to change catalog prices.\n"},{"id":"ecommerce.progression.shipping-authorization","owners":["ecommerce.progression.operations-access-specifications"],"requiresFeatures":["ecommerce.progression.fulfilment-queue"],"text":"## Shipping authorization\n\nThe server allows only staff and administrators to mark orders as shipped.\n"},{"id":"ecommerce.progression.order-ownership","owners":["ecommerce.progression.operations-access-specifications"],"requiresFeatures":["ecommerce.l2.order-cancellation-features"],"text":"## Order ownership\n\nThe server allows a customer to act only on that customer's own orders.\n"},{"id":"ecommerce.progression.review-access","owners":["ecommerce.progression.review-access-specifications"],"requiresFeatures":["ecommerce.feature.reviews"],"text":"## Review access\n\nOnly a customer who bought an item can review it.\n"},{"id":"ecommerce.progression.transfer-conservation","owners":["ecommerce.progression.inventory-conservation-specifications"],"requiresFeatures":["ecommerce.l2.stock-transfers-features"],"text":"## Stock conservation\n\nStock moves between warehouses without changing the total. A refused transfer changes nothing.\nWhen a purchase and a transfer overlap, the final total reflects the sold units exactly once.\n"},{"id":"ecommerce.progression.cancellation-conservation","owners":["ecommerce.progression.inventory-conservation-specifications"],"requiresFeatures":["ecommerce.l2.order-cancellation-features"],"text":"## Cancellation conservation\n\nCancelling an order restores its stock to the warehouse that supplied it. The restored total is\nthe same for current and newly opened clients.\n"},{"id":"ecommerce.l3.reservations","owners":["ecommerce.l3.reservations-features"],"text":"## Reservations\n\nAdding an item to a cart reserves its stock for 90 seconds. The cart shows the remaining time.\nCheckout consumes a live reservation. An expired reservation releases its stock and remains\nvisible as expired. Adding the item again renews the reservation.\n"},{"id":"ecommerce.l3.scheduled-restocks","owners":["ecommerce.l3.scheduled-restocks-features"],"text":"## Scheduled restocks\n\nAn admin can schedule and cancel a restock. Show pending restocks and their remaining\ntime. Show completed stock movements in a stock ledger.\n"},{"id":"ecommerce.l3.order-delivery","owners":["ecommerce.l3.order-delivery-features"],"text":"## Order delivery\n\nA shipped order becomes delivered 60 seconds after shipping. Show its status in the\ncustomer's order history and the staff view.\n"},{"id":"ecommerce.l3.cart-expiration","owners":["ecommerce.l3.cart-expiration-features"],"text":"## Cart expiration\n\nA cart with no activity for five minutes expires and releases its reservations. The customer\nsees an empty cart and an expiration notice.\n"},{"id":"ecommerce.l3.durable-reservations","owners":["ecommerce.l3.deferred-durability-specifications"],"requiresFeatures":["ecommerce.l3.reservations-features"],"text":"## Durable reservations\n\nPending reservations survive a backend restart.\n\n"},{"id":"ecommerce.progression.managed-support","owners":["ecommerce.progression.managed-support"],"text":"## Managed support cases\n\nCustomers and staff can exchange replies and update the status of a support case.\n"},{"id":"ecommerce.l3.durable-restocks","owners":["ecommerce.l3.deferred-durability-specifications"],"requiresFeatures":["ecommerce.l3.scheduled-restocks-features"],"text":"## Durable restocks\n\nPending restocks survive a backend restart.\n\n"},{"id":"ecommerce.l3.durable-order-delivery","owners":["ecommerce.l3.deferred-durability-specifications"],"requiresFeatures":["ecommerce.l3.order-delivery-features"],"text":"## Durable order delivery\n\nPending order delivery survives a backend restart.\n\n"},{"id":"ecommerce.l3.durable-cart-expiration","owners":["ecommerce.l3.deferred-durability-specifications"],"requiresFeatures":["ecommerce.l3.cart-expiration-features"],"text":"## Durable cart expiration\n\nPending cart expiration survives a backend restart.\n\n"},{"id":"ecommerce.l3.exactly-once-restocks","owners":["ecommerce.l3.deferred-integrity-specifications"],"requiresFeatures":["ecommerce.l3.scheduled-restocks-features"],"text":"## Exactly-once restocks\n\nRestarting the backend cannot apply a restock more than once.\n\n"},{"id":"ecommerce.l3.exactly-once-delivery","owners":["ecommerce.l3.deferred-integrity-specifications"],"requiresFeatures":["ecommerce.l3.order-delivery-features"],"text":"## Exactly-once delivery\n\nRestarting the backend cannot apply an order transition more than once.\n\n"},{"id":"ecommerce.l3.server-timed-restocks","owners":["ecommerce.l3.server-time-specifications"],"requiresFeatures":["ecommerce.l3.scheduled-restocks-features"],"text":"## Server-timed restocks\n\nA pending restock does not run early after a restart.\n\n"},{"id":"ecommerce.l3.server-timed-reservations","owners":["ecommerce.l3.server-time-specifications"],"requiresFeatures":["ecommerce.l3.reservations-features"],"text":"## Server-timed reservations\n\nA reservation expires without an open browser.\n\n"},{"id":"ecommerce.l3.deferred-access","owners":["ecommerce.l3.deferred-access-specifications"],"requiresFeatures":["ecommerce.l3.scheduled-restocks-features"],"text":"## Deferred-work access\n\nOnly an admin can schedule or cancel a restock.\n\n"},{"id":"ecommerce.l3.stock-conservation","owners":["ecommerce.l3.deferred-integrity-specifications"],"requiresFeatures":["ecommerce.l3.reservations-features"],"text":"## Stock conservation\n\nReservation expiry returns exactly the stock that the reservation took. Checkout does not take reserved stock twice.\n"},{"id":"ecommerce.progression.promotion-checkout","owners":["ecommerce.progression.promotion-checkout"],"text":"## Promotion checkout\n\nCustomers can apply an active promotion code to a cart. The final order records the applied\ndiscount. Expired and fully redeemed promotions are refused.\n"},{"id":"ecommerce.progression.stock-alerts","owners":["ecommerce.progression.stock-alerts"],"text":"## Stock alerts\n\nA signed-in customer can request an alert for an unavailable item. Show an alert when stock\nreturns.\n"},{"id":"ecommerce.progression.faceted-search","owners":["ecommerce.progression.faceted-search"],"text":"# Faceted search\n\nLet visitors filter the catalog by category, minimum price, maximum price, and availability.\nCombine the selected filters. While search text or any filter is active, order matching\nitems by name, with ten results per page. With no search text or active filter, use\nthe storefront's purchase ranking, breaking ties by item name. Clearing all search\ntext and filters returns to that ranking.\n"},{"id":"ecommerce.progression.personalized-recommendations","owners":["ecommerce.progression.personalized-recommendations"],"text":"# Personalized recommendations\n\nRecommend items from categories in the signed-in customer's purchase history. Exclude\nitems they already purchased. Order by global units sold, highest first, then by item name.\n"},{"id":"ecommerce.spec.search-ordering","owners":["ecommerce.spec.search-ordering"],"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.progression.faceted-search"],"text":"# Search ordering after purchases\n\nPurchases must not change the alphabetical order of active search or filter results.\nClearing all search text and filters restores the current purchase ranking.\n"},{"id":"ecommerce.l3.order-returns","owners":["ecommerce.l3.order-returns-features"],"text":"## Order returns\n\nA customer can return an item after the order ships for a refund of its purchase price.\nRestock the item and mark it returned in order history.\n"},{"id":"ecommerce.progression.order-support","owners":["ecommerce.progression.order-support"],"text":"## Order-linked support\n\nA customer can attach an order to a support case. Staff can inspect the linked order\nfrom the case.\n"},{"id":"ecommerce.progression.promotion-reporting","owners":["ecommerce.progression.promotion-reporting"],"text":"## Promotion reporting\n\nStaff can see each promotion's redemption count and revenue after discounts.\n"},{"id":"ecommerce.progression.delivery-notifications","owners":["ecommerce.progression.delivery-notifications"],"text":"## Delivery notifications\n\nNotify customers when their orders are delivered, using their notification preferences.\n"},{"id":"ecommerce.progression.automatic-reorder","owners":["ecommerce.progression.automatic-reorder"],"text":"# Automatic reorder rules\n\nWarehouse staff can manage automatic reorder rules. A rule names an item, a stock\nthreshold, and a restock quantity. Schedule a restock when stock falls from above the\nthreshold to the threshold or below.\nThe automatic restock is due 60 seconds after it is scheduled.\n"},{"id":"ecommerce.progression.cart-recovery","owners":["ecommerce.progression.cart-recovery"],"text":"# Cart recovery\n\nLet a signed-in customer restore an expired cart. Reserve each item again only when its full\nquantity is available. Restore the available items and list each item that could not be restored.\n"},{"id":"ecommerce.progression.recommendation-feedback","owners":["ecommerce.progression.recommendation-feedback"],"text":"## Recommendation feedback\n\nA customer can dismiss a recommendation from their list.\n"},{"id":"ecommerce.feature.store-credit","owners":["ecommerce.feature.store-credit"],"text":"## Store credit\n\nStaff can issue customer credit with a reference. Customers can see their balance and history and choose credit at cart checkout. Use credit first, up to the order total; record any remainder as the existing payment. Amounts use the shop currency and whole minor units. A reference identifies one grant.\n"},{"id":"ecommerce.feature.subscriptions","owners":["ecommerce.feature.subscriptions"],"text":"## Scheduled purchases\n\nCustomers can subscribe to an individual catalog item (not a bundle) and quantity for a chosen number of deliveries at a chosen interval. Use the item price at subscription creation. The first delivery is due after one interval. Each delivery creates an ordinary order and payment. Skip an unavailable delivery without charging; it still uses one delivery slot. Customers can pause, resume, or cancel future deliveries; a pause moves future due times by the pause duration.\n"},{"id":"ecommerce.progression.support-refunds","owners":["ecommerce.progression.support-refunds"],"text":"## Support refunds\n\nStaff can refund an entire order from its support case. A successful refund resolves\nthe case. Show the refund amount and case status.\n\nA refund does not prevent a later physical return of shipped goods. Refund only\nthe amount not already refunded, and restock goods when they are returned.\n"},{"id":"ecommerce.spec.access-control.automatic-reorder-access","owners":["ecommerce.spec.access-control"],"requiresFeatures":["ecommerce.progression.automatic-reorder"],"text":"## automatic-reorder-access\n\nOnly warehouse staff can manage automatic reorder rules.\n\n"},{"id":"ecommerce.spec.access-control.recommendation-profile-isolation","owners":["ecommerce.spec.access-control"],"requiresFeatures":["ecommerce.progression.personalized-recommendations"],"text":"## recommendation-profile-isolation\n\nCustomer recommendation profiles are isolated.\n\n"},{"id":"ecommerce.spec.access-control.staff-activity-privacy","owners":["ecommerce.spec.access-control"],"requiresFeatures":["ecommerce.progression.staff-activity"],"text":"## staff-activity-privacy\n\nCustomers cannot open staff activity history.\n\n"},{"id":"ecommerce.spec.access-control.order-support-ownership","owners":["ecommerce.spec.access-control"],"requiresFeatures":["ecommerce.progression.order-support"],"text":"## order-support-ownership\n\nA customer cannot attach or inspect another customer's order.\n\n"},{"id":"ecommerce.spec.access-control.delivery-notification-privacy","owners":["ecommerce.spec.access-control"],"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.progression.delivery-notifications","ecommerce.progression.fulfilment-queue"],"text":"## delivery-notification-privacy\n\nDelivery notifications are private to the order owner.\n\n"},{"id":"ecommerce.spec.access-control.support-refund-access","owners":["ecommerce.spec.access-control"],"requiresFeatures":["ecommerce.progression.support-refunds"],"text":"## support-refund-access\n\nOnly authorized staff can refund an order from a support case.\n\n"},{"id":"ecommerce.spec.access-control.recommendation-feedback-privacy","owners":["ecommerce.spec.access-control"],"requiresFeatures":["ecommerce.progression.recommendation-feedback"],"text":"## recommendation-feedback-privacy\n\nRecommendation feedback belongs to one customer.\n\n"},{"id":"ecommerce.spec.state-durability.recommendation-feedback-restart","owners":["ecommerce.spec.state-durability"],"requiresFeatures":["ecommerce.progression.recommendation-feedback"],"text":"## recommendation-feedback-restart\n\nDismissed recommendations stay dismissed after reconnecting or restarting the server.\n\n"},{"id":"ecommerce.spec.transactional-integrity.automatic-reorder-deduplication","owners":["ecommerce.spec.transactional-integrity"],"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.progression.automatic-reorder"],"text":"## automatic-reorder-deduplication\n\nA pending automatic restock is not scheduled twice.\n\n"},{"id":"ecommerce.spec.transactional-integrity.payment-deduplication","owners":["ecommerce.spec.transactional-integrity"],"requiresFeatures":["ecommerce.progression.payment-records"],"text":"## payment-deduplication\n\nA checkout does not create duplicate payments.\n\n"},{"id":"ecommerce.spec.transactional-integrity.support-refund-accounting","owners":["ecommerce.spec.transactional-integrity"],"requiresFeatures":["ecommerce.progression.support-refunds"],"text":"## support-refund-accounting\n\nThe recorded refund equals the amount paid and is applied only once.\n"},{"id":"ecommerce.feature.split-tender-refunds","owners":["ecommerce.feature.split-tender-refunds"],"text":"## Refunds with store credit\n\nExtend support refunds and item returns to orders paid with credit and another payment. Return each part to its original source. A full refund restores the original credit portion to the customer balance and refunds the original external portion.\n"},{"id":"ecommerce.spec.bundle-integrity.product-bundles","owners":["ecommerce.spec.bundle-integrity"],"requiresFeatures":["ecommerce.feature.product-bundles"],"text":"## Product bundles\n\nOnly authorized staff can change bundles.\n\n"},{"id":"ecommerce.spec.bundle-integrity.bundle-checkout","owners":["ecommerce.spec.bundle-integrity"],"requiresFeatures":["ecommerce.feature.bundle-checkout"],"text":"## Bundle checkout\n\nReserve all components or none. Competing purchases share the same stock. Release component reservations when the cart expires or the bundle is removed.\n\n"},{"id":"ecommerce.spec.bundle-integrity.bundle-returns","owners":["ecommerce.spec.bundle-integrity"],"requiresFeatures":["ecommerce.feature.bundle-returns"],"text":"## Bundle returns\n\nReturn the original component allocations and price paid. Repeating a return must not change stock or refunds again. Customers cannot return another account's order.\n\n"},{"id":"ecommerce.spec.store-credit.store-credit","owners":["ecommerce.spec.store-credit"],"requiresFeatures":["ecommerce.feature.store-credit"],"text":"## Store credit\n\nOnly authorized staff can grant credit. Repeating a reference must not issue credit twice. Concurrent checkout must not duplicate the order or credit use. Accepted credit survives a backend restart.\n\n"},{"id":"ecommerce.spec.split-tender-refunds.split-tender-refunds","owners":["ecommerce.spec.split-tender-refunds"],"requiresFeatures":["ecommerce.feature.split-tender-refunds"],"text":"## Split-tender refunds\n\nConcurrent or repeated refunds must restore each original payment portion only once. The resulting balance and refund records survive a backend restart.\n\n"},{"id":"ecommerce.spec.subscriptions.subscriptions","owners":["ecommerce.spec.subscriptions"],"requiresFeatures":["ecommerce.feature.subscriptions"],"text":"## Scheduled purchases\n\nPending deliveries and pauses survive a backend restart. Process elapsed pending slots after recovery. Completed delivery slots must not run again. Customers cannot change another account's subscription.\n"},{"id":"ecommerce.feature.product-bundles","owners":["ecommerce.feature.product-bundles"],"text":"## Product bundles\n\nCatalog staff can create and edit a named bundle of existing products, with a quantity\nfor each component and one bundle price. Show bundles and their components in the catalog.\nBundles contain products only, not other bundles.\n"},{"id":"ecommerce.feature.bundle-checkout","owners":["ecommerce.feature.bundle-checkout"],"text":"## Bundle checkout\n\nCustomers can add a whole bundle to their cart and buy it through checkout. Its components\nuse the existing stock reservations and reservation lifetime. Removing a bundle releases\nits reservation. Show the bundle as one order line at its bundle price.\n"},{"id":"ecommerce.feature.bundle-returns","owners":["ecommerce.feature.bundle-returns"],"text":"## Bundle returns\n\nCustomers can return a shipped bundle as a whole. Restore the purchased component quantities\nto their original warehouses and refund the price paid. Show the return and refund on the\norder. Partial bundle returns are not supported.\n"}]},"track":"ecommerce"},"execution":{"capabilities":["backend-lifecycle","browser","concurrent-actors","database-observation","database-read","direct-database-write","direct-server-call","process-crash","request-replay"],"execution":[{"checkGroups":[{"checkGroupId":"accounts","feature":{"actors":["shopper"],"criteria":[{"id":"1a","steps":[{"actor":"shopper","do":"signUp","name":"ann"},{"actor":"shopper","contains":"ann","do":"expect","testid":"current-user","within":6000}]}],"id":1,"setup":[]},"packId":"ecommerce.feature.accounts","role":"feature","source":"scenarios/01-account-create.json"}],"id":"selected-source-001","scenario":{"level":1,"writeUrlPattern":null},"source":"scenarios/01-account-create.json"},{"checkGroups":[{"checkGroupId":"accounts","feature":{"actors":["owner","impostor"],"criteria":[{"id":"1b","steps":[{"actor":"impostor","do":"signUp","expectFailure":true,"name":"ann","password":"different-pw"},{"actor":"impostor","do":"expect","testid":"auth-error","within":6000},{"absent":true,"actor":"impostor","do":"expect","testid":"current-user"}]}],"id":1,"setup":[{"actor":"owner","do":"signUp","name":"ann"}]},"packId":"ecommerce.feature.accounts","role":"feature","source":"scenarios/01-account-duplicate.json"}],"id":"selected-source-002","scenario":{"level":1,"writeUrlPattern":null},"source":"scenarios/01-account-duplicate.json"},{"checkGroups":[{"checkGroupId":"accounts","feature":{"actors":["owner","impostor"],"criteria":[{"id":"1c","steps":[{"actor":"impostor","do":"signIn","expectFailure":true,"name":"ann","password":"wrong-pw"},{"actor":"impostor","do":"expect","testid":"auth-error","within":6000},{"absent":true,"actor":"impostor","do":"expect","testid":"current-user"}]}],"id":1,"setup":[{"actor":"owner","do":"signUp","name":"ann"}]},"packId":"ecommerce.feature.accounts","role":"feature","source":"scenarios/01-account-password.json"}],"id":"selected-source-003","scenario":{"level":1,"writeUrlPattern":null},"source":"scenarios/01-account-password.json"},{"checkGroups":[{"checkGroupId":"session-reload","feature":{"actors":["shopper"],"criteria":[{"id":"1e","steps":[{"actor":"shopper","do":"reload","settleMs":4000},{"actor":"shopper","contains":"ann","do":"expect","testid":"current-user","within":6000}]}],"id":1,"setup":[{"actor":"shopper","do":"signUp","name":"ann"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.state-durability","requiresFeatures":["ecommerce.feature.accounts"],"role":"guarantee","source":"scenarios/01-account-reload.json"}],"id":"selected-source-004","scenario":{"level":1,"writeUrlPattern":null},"source":"scenarios/01-account-reload.json"},{"checkGroups":[{"checkGroupId":"accounts","feature":{"actors":["shopper"],"criteria":[{"id":"1d","steps":[{"actor":"shopper","do":"click","testid":"current-user","unlessVisible":"signout"},{"actor":"shopper","do":"click","testid":"signout"},{"actor":"shopper","do":"waitUntilAbsent","testid":"current-user","within":6000},{"actor":"shopper","do":"signIn","name":"ann"},{"actor":"shopper","contains":"ann","do":"expect","testid":"current-user","within":6000}]}],"id":1,"setup":[{"actor":"shopper","do":"signUp","name":"ann"}]},"packId":"ecommerce.feature.accounts","role":"feature","source":"scenarios/01-account-signout.json"}],"id":"selected-source-005","scenario":{"level":1,"writeUrlPattern":null},"source":"scenarios/01-account-signout.json"},{"checkGroups":[{"checkGroupId":"admin-write","feature":{"actors":["admin","staff"],"criteria":[{"id":"103a","steps":[{"actor":"staff","as":"purifier-before-control","do":"recordNumber","in":{"contains":"Air Purifier","testid":"item-card"},"testid":"item-stock"},{"action":"restock","actor":"admin","do":"callAction","input":{"attribute":"data-restock-input","contains":"Air Purifier","testid":"admin-location-row"},"namedAction":{"args":[0,0,1],"id":"restock","params":[{"in":"body","name":"itemId","wireType":"u64"},{"in":"body","name":"warehouseId","wireType":"u64"},{"in":"body","name":"quantity"}],"path":"/api/admin/restock","reducer":"admin_restock"},"settleMs":2000},{"actor":"admin","do":"expectActionOutcome","outcome":"accepted"},{"actor":"staff","do":"reload","settleMs":2000},{"actor":"staff","do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026","readyTestid":"current-user"},{"actor":"staff","do":"expectNumber","in":{"contains":"Air Purifier","testid":"item-card"},"plus":1,"relativeTo":"purifier-before-control","testid":"item-stock"}]}],"id":103,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"admin","do":"click","testid":"admin-link"}]},"packId":"ecommerce.feature.warehouse-admin","role":"feature","source":"scenarios/01-admin-write-staff.json"},{"checkGroupId":"warehouse-write-boundary","feature":{"actors":["admin","staff"],"criteria":[{"id":"103b","steps":[{"action":"restock","actor":"admin","do":"callAction","input":{"attribute":"data-restock-input","contains":"Air Purifier","testid":"admin-location-row"},"namedAction":{"args":[0,0,1],"id":"restock","params":[{"in":"body","name":"itemId","wireType":"u64"},{"in":"body","name":"warehouseId","wireType":"u64"},{"in":"body","name":"quantity"}],"path":"/api/admin/restock","reducer":"admin_restock"},"settleMs":2000},{"actor":"admin","do":"expectActionOutcome","outcome":"accepted"},{"actor":"staff","do":"reload","settleMs":2000},{"actor":"staff","do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026","readyTestid":"current-user"},{"actor":"staff","as":"purifier-before-refusal","do":"recordNumber","in":{"contains":"Air Purifier","testid":"item-card"},"testid":"item-stock"},{"action":"restock","actor":"staff","do":"callAction","from":"admin","input":{"attribute":"data-restock-input","contains":"Air Purifier","testid":"admin-location-row"},"namedAction":{"args":[0,0,1],"id":"restock","params":[{"in":"body","name":"itemId","wireType":"u64"},{"in":"body","name":"warehouseId","wireType":"u64"},{"in":"body","name":"quantity"}],"path":"/api/admin/restock","reducer":"admin_restock"},"settleMs":2000},{"actor":"staff","do":"expectActionOutcome","outcome":"refused","routeProvenBy":"admin"},{"actor":"staff","do":"reload","settleMs":2000},{"actor":"staff","do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026","readyTestid":"current-user"},{"actor":"staff","do":"expectNumber","in":{"contains":"Air Purifier","testid":"item-card"},"plus":0,"relativeTo":"purifier-before-refusal","testid":"item-stock"}]}],"id":103,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"admin","do":"click","testid":"admin-link"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","requiresFeatures":["ecommerce.feature.warehouse-admin"],"role":"guarantee","source":"scenarios/01-admin-write-staff.json"}],"id":"selected-source-006","scenario":{"level":1,"writeUrlPattern":null},"source":"scenarios/01-admin-write-staff.json"},{"checkGroups":[{"checkGroupId":"purchase-stock","feature":{"actors":["buyer","watcher","visitor"],"criteria":[{"id":"3b","steps":[{"actor":"watcher","do":"expectNumber","equals":100,"in":{"contains":"Espresso Machine","testid":"item-card"},"testid":"item-stock"},{"actor":"buyer","do":"click","in":{"contains":"Espresso Machine","testid":"item-card"},"testid":"buy-now"},{"actor":"watcher","do":"expectNumber","equals":99,"in":{"contains":"Espresso Machine","testid":"item-card"},"testid":"item-stock"},{"actor":"visitor","do":"expectNumber","equals":99,"in":{"contains":"Espresso Machine","testid":"item-card"},"testid":"item-stock"}]}],"id":3,"setup":[{"actor":"buyer","do":"signUp","name":"eli"},{"actor":"watcher","do":"signUp","name":"fay"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.live-state","requiresFeatures":["ecommerce.feature.catalog-items","ecommerce.feature.purchasing"],"role":"guarantee","source":"scenarios/01-buying.json"}],"id":"selected-source-007","scenario":{"level":1,"writeUrlPattern":null},"source":"scenarios/01-buying.json"},{"checkGroups":[{"checkGroupId":"cart-boundary","feature":{"actors":["owner","stranger"],"criteria":[{"id":"109a","steps":[{"action":"cart-add","actor":"stranger","do":"callAction","input":{"attribute":"data-buy-input","contains":"Coffee Grinder","testid":"item-card"},"namedAction":{"args":[0],"id":"cart-add","params":[{"in":"body","name":"itemId","wireType":"u64"}],"path":"/api/cart","reducer":"add_to_cart"},"settleMs":2000},{"actor":"stranger","do":"expectActionOutcome","outcome":"accepted"},{"actor":"owner","do":"reload","settleMs":1500},{"actor":"owner","do":"ensureSignedIn","name":"vic","readyTestid":"current-user"},{"actor":"owner","do":"click","ifAvailable":true,"testid":"overlay-close"},{"actor":"owner","do":"click","ifAvailable":true,"testid":"catalog-link"},{"actor":"owner","do":"click","testid":"cart-toggle","unlessVisible":"cart-total"},{"actor":"stranger","do":"reload","settleMs":1500},{"actor":"stranger","do":"ensureSignedIn","name":"wes","readyTestid":"current-user"},{"actor":"stranger","do":"click","ifAvailable":true,"testid":"overlay-close"},{"actor":"stranger","do":"click","ifAvailable":true,"testid":"catalog-link"},{"actor":"owner","contains":"Coffee Grinder","count":1,"do":"expect","testid":"cart-item"},{"actor":"owner","do":"expectNumber","equals":1,"in":{"contains":"Coffee Grinder","testid":"cart-item"},"testid":"cart-quantity"},{"actor":"stranger","do":"click","testid":"cart-toggle","unlessVisible":"cart-total"},{"actor":"stranger","contains":"Coffee Grinder","count":1,"do":"expect","testid":"cart-item"},{"actor":"stranger","do":"expectNumber","equals":1,"in":{"contains":"Coffee Grinder","testid":"cart-item"},"testid":"cart-quantity"}]},{"id":"109b","steps":[{"actor":"owner","as":"cart-total-before-invalid","do":"recordNumber","testid":"cart-total"},{"actor":"owner","as":"cart-quantity-before-invalid","do":"recordNumber","in":{"contains":"Coffee Grinder","testid":"cart-item"},"testid":"cart-quantity"},{"action":"cart-set-quantity","actor":"owner","do":"callAction","input":{"attribute":"data-cart-input","contains":"Coffee Grinder","testid":"cart-item"},"namedAction":{"args":[0,-3],"id":"cart-set-quantity","method":"PATCH","params":[{"in":"path","name":"itemId","placeholder":":itemId","wireType":"u64"},{"in":"body","name":"quantity"}],"path":"/api/cart/:itemId","reducer":"update_cart_quantity"},"settleMs":2000},{"actor":"owner","do":"expectActionOutcome","outcome":"validation-refused"},{"actor":"owner","do":"reload","settleMs":1500},{"actor":"owner","do":"ensureSignedIn","name":"vic","readyTestid":"current-user"},{"actor":"owner","do":"click","ifAvailable":true,"testid":"overlay-close"},{"actor":"owner","do":"click","ifAvailable":true,"testid":"catalog-link"},{"actor":"owner","do":"click","testid":"cart-toggle","unlessVisible":"cart-total"},{"actor":"owner","do":"expectNumber","plus":0,"relativeTo":"cart-total-before-invalid","testid":"cart-total"},{"actor":"owner","do":"expectNumber","in":{"contains":"Coffee Grinder","testid":"cart-item"},"plus":0,"relativeTo":"cart-quantity-before-invalid","testid":"cart-quantity"}]}],"id":109,"setup":[{"actor":"owner","do":"signUp","name":"vic"},{"actor":"stranger","do":"signUp","name":"wes"},{"actor":"owner","do":"click","in":{"contains":"Coffee Grinder","testid":"item-card"},"testid":"add-to-cart"},{"actor":"owner","do":"wait","ms":1500},{"actor":"owner","do":"click","testid":"cart-toggle","unlessVisible":"cart-total"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","requiresFeatures":["ecommerce.feature.cart"],"role":"guarantee","source":"scenarios/01-cart-boundary.json"}],"id":"selected-source-008","scenario":{"level":1,"writeUrlPattern":"\\/api\\/|\\/items|\\/cart|\\/orders|\\/checkout|\\/buy|\\/reviews|\\/stock|\\/restock|\\/warehouses"},"source":"scenarios/01-cart-boundary.json"},{"checkGroups":[{"checkGroupId":"cart-reload","feature":{"actors":["quantity","reload","live1","live2","checkout"],"criteria":[{"id":"4b","steps":[{"actor":"reload","do":"click","in":{"contains":"Laptop Stand","testid":"item-card"},"testid":"add-to-cart"},{"actor":"reload","do":"click","testid":"cart-toggle","unlessVisible":"cart-total"},{"actor":"reload","contains":"Laptop Stand","do":"expect","testid":"cart-item","within":10000},{"actor":"reload","do":"reload","settleMs":3000},{"actor":"reload","do":"ensureSignedIn","name":"omar","readyTestid":"current-user"},{"actor":"reload","do":"click","testid":"cart-toggle","unlessVisible":"cart-total"},{"actor":"reload","contains":"Laptop Stand","do":"expect","testid":"cart-item"}]}],"id":4,"setup":[{"actor":"quantity","do":"signUp","name":"nora"},{"actor":"reload","do":"signUp","name":"omar"},{"actor":"live1","do":"signUp","name":"pia"},{"actor":"checkout","do":"signUp","name":"quinn"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.state-durability","requiresFeatures":["ecommerce.feature.cart"],"role":"guarantee","source":"scenarios/01-cart.json"},{"checkGroupId":"shared-cart","feature":{"actors":["quantity","reload","live1","live2","checkout"],"criteria":[{"id":"4c","steps":[{"actor":"live2","do":"signIn","name":"pia"},{"actor":"live2","do":"click","testid":"cart-toggle","unlessVisible":"cart-total"},{"actor":"live1","do":"click","in":{"contains":"Induction Cooktop","testid":"item-card"},"testid":"add-to-cart"},{"actor":"live2","contains":"Induction Cooktop","do":"expect","testid":"cart-item","within":10000}]}],"id":4,"setup":[{"actor":"quantity","do":"signUp","name":"nora"},{"actor":"reload","do":"signUp","name":"omar"},{"actor":"live1","do":"signUp","name":"pia"},{"actor":"checkout","do":"signUp","name":"quinn"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.live-state","requiresFeatures":["ecommerce.feature.cart"],"role":"guarantee","source":"scenarios/01-cart.json"}],"id":"selected-source-009","scenario":{"level":1,"writeUrlPattern":null},"source":"scenarios/01-cart.json"},{"checkGroups":[{"checkGroupId":"catalog-ranking","feature":{"actors":["visitor"],"criteria":[{"id":"2b","steps":[{"actor":"visitor","do":"expectSequence","equals":["Air Purifier","Bluetooth Speaker","Coffee Grinder","Desk Lamp","Espresso Machine","Gaming Mouse","Headphones","Induction Cooktop","Keyboard","Laptop Stand"],"in":{"testid":"item-list"},"testid":"item-name"}]}],"id":2,"setup":[]},"packId":"ecommerce.feature.catalog-discovery","role":"feature","source":"scenarios/01-catalog-ranking.json","stablePackId":"ecommerce.feature.catalog"}],"id":"selected-source-010","scenario":{"level":1,"writeUrlPattern":null},"source":"scenarios/01-catalog-ranking.json"},{"checkGroups":[{"checkGroupId":"catalog-search","feature":{"actors":["visitor"],"criteria":[{"id":"2d","steps":[{"actor":"visitor","do":"fill","enter":true,"settleMs":1500,"testid":"search-input","text":"mirrorLESS"},{"actor":"visitor","contains":"Mirrorless Camera","do":"expect","in":{"testid":"search-results"},"testid":"item-card"}]}],"id":2,"setup":[]},"packId":"ecommerce.feature.catalog-discovery","role":"feature","source":"scenarios/01-catalog-search.json","stablePackId":"ecommerce.feature.catalog"}],"id":"selected-source-011","scenario":{"level":1,"writeUrlPattern":null},"source":"scenarios/01-catalog-search.json"},{"checkGroups":[{"checkGroupId":"catalog-values","feature":{"actors":["visitor"],"criteria":[{"id":"2a","steps":[{"actor":"visitor","contains":"Air Purifier","do":"expect","testid":"item-card"},{"actor":"visitor","do":"expectNumber","equals":189,"in":{"contains":"Air Purifier","testid":"item-card"},"testid":"item-price"},{"actor":"visitor","do":"expectNumber","equals":100,"in":{"contains":"Air Purifier","testid":"item-card"},"testid":"item-stock"}]}],"id":2,"setup":[]},"packId":"ecommerce.feature.catalog-items","role":"feature","source":"scenarios/01-catalog-values.json","stablePackId":"ecommerce.feature.catalog"}],"id":"selected-source-012","scenario":{"level":1,"writeUrlPattern":null},"source":"scenarios/01-catalog-values.json"},{"checkGroups":[{"checkGroupId":"ranking","feature":{"actors":["buyer","visitor","inspector"],"criteria":[{"id":"2c","steps":[{"actor":"buyer","do":"click","in":{"contains":"Coffee Grinder","testid":"item-card"},"testid":"buy-now"},{"actor":"visitor","do":"expectSequence","equals":["Coffee Grinder","Air Purifier","Bluetooth Speaker","Desk Lamp","Espresso Machine","Gaming Mouse","Headphones","Induction Cooktop","Keyboard","Laptop Stand"],"in":{"testid":"item-list"},"testid":"item-name","within":10000},{"actors":["buyer","visitor"],"do":"expectAgreement","in":{"contains":"Coffee Grinder","testid":"item-card"},"numeric":true,"testid":"item-stock"}]}],"id":2,"setup":[{"actor":"buyer","do":"signUp","name":"dov"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.live-state","requiresFeatures":["ecommerce.feature.catalog-items","ecommerce.feature.purchasing"],"role":"guarantee","source":"scenarios/01-core.json"}],"id":"selected-source-013","scenario":{"level":1,"writeUrlPattern":null},"source":"scenarios/01-core.json"},{"checkGroups":[{"checkGroupId":"duplicate-checkout","feature":{"actors":["tab1","tab2","filler"],"criteria":[{"id":"203a","steps":[{"actor":"tab1","contains":"Gaming Mouse","count":1,"do":"expect","testid":"cart-item"},{"actor":"tab1","do":"expectNumber","equals":2,"in":{"contains":"Gaming Mouse","testid":"cart-item"},"testid":"cart-quantity"}]},{"id":"203b","steps":[{"actor":"tab1","do":"click","testid":"checkout-submit"},{"actor":"tab1","do":"wait","ms":2500},{"actor":"filler","as":"keyboard-before-checkout","do":"recordNumber","in":{"contains":"Keyboard","testid":"item-card"},"testid":"item-stock"},{"account":"{user:twin}","as":"checkout-before","do":"dbRecordCheckout","item":"Keyboard","storage":{"cart":true,"kind":"order-data","warehouses":false}},{"actor":"filler","do":"click","in":{"contains":"Keyboard","testid":"item-card"},"testid":"add-to-cart"},{"actor":"filler","do":"wait","ms":2000},{"account":"{user:twin}","as":"checkout-prepared","do":"dbRecordCheckout","item":"Keyboard","storage":{"cart":true,"kind":"order-data","warehouses":false}},{"action":"checkout","actors":["tab1","tab2"],"do":"callConcurrently","settleMs":5000},{"do":"expectCallOutcomes"},{"before":"checkout-before","do":"dbExpectCheckout","prepared":"checkout-prepared","quantity":1},{"actor":"filler","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"filler","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"filler","contains":"Keyboard","count":1,"do":"expect","testid":"order-item"},{"actor":"filler","do":"reload","settleMs":2000},{"actor":"filler","do":"ensureSignedIn","name":"twin","readyTestid":"current-user"},{"actor":"filler","do":"click","ifAvailable":true,"testid":"overlay-close"},{"actor":"filler","do":"click","ifAvailable":true,"testid":"catalog-link"},{"actor":"filler","do":"expectNumber","in":{"contains":"Keyboard","testid":"item-card"},"plus":-1,"relativeTo":"keyboard-before-checkout","testid":"item-stock"}]}],"id":203,"setup":[{"actor":"tab1","do":"signUp","name":"twin"},{"actor":"tab2","do":"signIn","name":"twin"},{"actor":"filler","do":"signIn","name":"twin"},{"actors":["tab1","tab2"],"do":"clickConcurrently","in":{"contains":"Gaming Mouse","testid":"item-card"},"settleMs":4000,"testid":"add-to-cart"},{"actor":"tab1","do":"reload","settleMs":2500},{"actor":"tab1","do":"ensureSignedIn","name":"twin","readyTestid":"current-user"},{"actor":"tab1","do":"click","testid":"cart-toggle","unlessVisible":"cart-total"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.concurrency-safety","requiresFeatures":["ecommerce.feature.checkout"],"role":"guarantee","source":"scenarios/01-duplicate-checkout.json"}],"id":"selected-source-014","scenario":{"level":1,"writeUrlPattern":"\\/api\\/|\\/items|\\/cart|\\/orders|\\/checkout|\\/buy|\\/reviews|\\/stock|\\/restock|\\/warehouses"},"source":"scenarios/01-duplicate-checkout.json"},{"checkGroups":[{"checkGroupId":"external-stock","feature":{"actors":["viewer"],"criteria":[{"id":"901a","steps":[{"do":"dbSetStock","item":"Desk Lamp","quantity":5,"settleMs":4000,"warehouse":"East"},{"actor":"viewer","do":"expectNumber","equals":50,"in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"item-stock","within":10000}]}],"id":901,"setup":[{"actor":"viewer","do":"expectNumber","equals":100,"in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"item-stock","within":10000}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.external-data-sync","requiresFeatures":["ecommerce.feature.warehouse-admin"],"role":"guarantee","source":"scenarios/01-external-live-sync.json"}],"id":"selected-source-015","scenario":{"level":1,"writeUrlPattern":"\\/api\\/|\\/items|\\/stock|\\/warehouses"},"source":"scenarios/01-external-live-sync.json"},{"checkGroups":[{"checkGroupId":"external-stock","feature":{"actors":["viewer"],"criteria":[{"id":"901d","steps":[{"actor":"viewer","do":"setOffline","offline":true,"settleMs":1000},{"do":"dbSetStock","item":"Desk Lamp","quantity":7,"settleMs":4000,"warehouse":"East"},{"actor":"viewer","do":"setOffline","offline":false,"settleMs":1000},{"actor":"viewer","do":"expectNumber","equals":52,"in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"item-stock","within":20000}]}],"id":901,"setup":[{"actor":"viewer","do":"expectNumber","equals":100,"in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"item-stock","within":10000}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.external-data-sync","requiresFeatures":["ecommerce.feature.warehouse-admin"],"role":"guarantee","source":"scenarios/01-external-reconnect-sync.json"}],"id":"selected-source-016","scenario":{"level":1,"writeUrlPattern":"\\/api\\/|\\/items|\\/stock|\\/warehouses"},"source":"scenarios/01-external-reconnect-sync.json"},{"checkGroups":[{"checkGroupId":"external-stock","feature":{"actors":["viewer"],"criteria":[{"id":"901b","steps":[{"do":"dbSetStock","item":"Desk Lamp","quantity":5,"settleMs":1000,"warehouse":"East"},{"actor":"viewer","do":"reload","settleMs":3000},{"actor":"viewer","do":"expectNumber","equals":50,"in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"item-stock","within":10000}]}],"id":901,"setup":[{"actor":"viewer","do":"expectNumber","equals":100,"in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"item-stock","within":10000}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.external-data-sync","requiresFeatures":["ecommerce.feature.warehouse-admin"],"role":"guarantee","source":"scenarios/01-external-reload-sync.json"}],"id":"selected-source-017","scenario":{"level":1,"writeUrlPattern":"\\/api\\/|\\/items|\\/stock|\\/warehouses"},"source":"scenarios/01-external-reload-sync.json"},{"checkGroups":[{"checkGroupId":"external-stock","feature":{"actors":["viewer"],"criteria":[{"id":"901c","steps":[{"do":"stopAppServer"},{"do":"dbSetStock","item":"Desk Lamp","quantity":10,"settleMs":4000,"warehouse":"West"},{"do":"startAppServer"},{"actor":"viewer","do":"expectNumber","equals":65,"in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"item-stock","within":20000}]}],"id":901,"setup":[{"actor":"viewer","do":"expectNumber","equals":100,"in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"item-stock","within":10000}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.external-data-sync","requiresFeatures":["ecommerce.feature.warehouse-admin"],"role":"guarantee","source":"scenarios/01-external-server-restart-sync.json"}],"id":"selected-source-018","scenario":{"level":1,"writeUrlPattern":"\\/api\\/|\\/items|\\/stock|\\/warehouses"},"source":"scenarios/01-external-server-restart-sync.json"},{"checkGroups":[{"checkGroupId":"last-unit","feature":{"actors":["admin","a","b","c","d","e","f"],"criteria":[{"id":"201a","steps":[{"do":"dbExpectStock","equals":0,"item":"Air Purifier","warehouse":"East"},{"do":"dbExpectStock","equals":0,"item":"Air Purifier","warehouse":"West"},{"actor":"a","do":"expectNumber","equals":0,"in":{"contains":"Air Purifier","testid":"item-card"},"testid":"item-stock"},{"actors":["a","b","c","d","e","f"],"do":"expectAgreement","in":{"contains":"Air Purifier","testid":"item-card"},"numeric":true,"testid":"item-stock"}]},{"id":"201c","steps":[{"actor":"admin","do":"reload","settleMs":1000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"admin","do":"click","testid":"admin-link","unlessVisible":"admin-revenue"},{"actor":"admin","do":"expectNumber","plus":567,"relativeTo":"revenue-before-last-unit","testid":"admin-revenue","within":10000}]},{"id":"201b","steps":[{"before":{"a":"buy-a","b":"buy-b","c":"buy-c","d":"buy-d","e":"buy-e","f":"buy-f"},"do":"dbExpectPurchases","purchases":3},{"actor":"a","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"a","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"b","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"b","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"c","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"c","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"d","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"d","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"e","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"e","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"f","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"f","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actors":["a","b","c","d","e","f"],"contains":"Air Purifier","do":"expectActorsWith","equals":3,"maxEach":1,"testid":"order-item"},{"do":"dbSetStock","item":"Air Purifier","quantity":2,"settleMs":250,"warehouse":"East"},{"do":"dbSetStock","item":"Air Purifier","quantity":2,"settleMs":250,"warehouse":"West"},{"actor":"a","do":"reload","settleMs":1000},{"actor":"a","do":"ensureSignedIn","name":"c1","readyTestid":"current-user"},{"actor":"a","do":"click","ifAvailable":true,"testid":"catalog-link"},{"account":"{user:c1}","as":"ample-a","do":"dbRecordCheckout","item":"Air Purifier","storage":{"cart":false,"kind":"order-data","warehouses":true}},{"account":"{user:c2}","as":"ample-b","do":"dbRecordCheckout","item":"Air Purifier","storage":{"cart":false,"kind":"order-data","warehouses":true}},{"action":"buy","actors":["a","b"],"do":"callConcurrently","from":"a","input":{"attribute":"data-buy-input","contains":"Air Purifier","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"},"requests":4,"settleMs":3000},{"do":"expectCallOutcomes"},{"before":{"a":"ample-a","b":"ample-b"},"do":"dbExpectPurchases","purchases":4}]}],"id":201,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"click","testid":"admin-link"},{"actor":"admin","as":"revenue-before-last-unit","do":"recordNumber","testid":"admin-revenue"},{"do":"dbSetStock","item":"Air Purifier","quantity":2,"settleMs":250,"warehouse":"East"},{"do":"dbSetStock","item":"Air Purifier","quantity":1,"settleMs":250,"warehouse":"West"},{"actor":"a","do":"signUp","name":"c1"},{"actor":"b","do":"signUp","name":"c2"},{"actor":"c","do":"signUp","name":"c3"},{"actor":"d","do":"signUp","name":"c4"},{"actor":"e","do":"signUp","name":"c5"},{"actor":"f","do":"signUp","name":"c6"},{"account":"{user:c1}","as":"buy-a","do":"dbRecordCheckout","item":"Air Purifier","storage":{"cart":false,"kind":"order-data","warehouses":true}},{"account":"{user:c2}","as":"buy-b","do":"dbRecordCheckout","item":"Air Purifier","storage":{"cart":false,"kind":"order-data","warehouses":true}},{"account":"{user:c3}","as":"buy-c","do":"dbRecordCheckout","item":"Air Purifier","storage":{"cart":false,"kind":"order-data","warehouses":true}},{"account":"{user:c4}","as":"buy-d","do":"dbRecordCheckout","item":"Air Purifier","storage":{"cart":false,"kind":"order-data","warehouses":true}},{"account":"{user:c5}","as":"buy-e","do":"dbRecordCheckout","item":"Air Purifier","storage":{"cart":false,"kind":"order-data","warehouses":true}},{"account":"{user:c6}","as":"buy-f","do":"dbRecordCheckout","item":"Air Purifier","storage":{"cart":false,"kind":"order-data","warehouses":true}},{"action":"buy","actors":["a","b","c","d","e","f"],"do":"callConcurrently","input":{"attribute":"data-buy-input","contains":"Air Purifier","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"},"settleMs":6000},{"do":"expectCallOutcomes"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.concurrency-safety","requiresFeatures":["ecommerce.feature.catalog-items","ecommerce.feature.purchasing","ecommerce.feature.warehouse-admin"],"role":"guarantee","source":"scenarios/01-last-unit.json"}],"id":"selected-source-019","scenario":{"level":1,"writeUrlPattern":"\\/api\\/|\\/items|\\/cart|\\/orders|\\/checkout|\\/buy|\\/reviews|\\/stock|\\/restock|\\/warehouses"},"source":"scenarios/01-last-unit.json"},{"checkGroups":[{"checkGroupId":"order-ownership","feature":{"actors":["one","two"],"criteria":[{"id":"106a","steps":[{"actor":"one","do":"click","in":{"contains":"Coffee Grinder","testid":"item-card"},"testid":"buy-now"},{"actor":"two","do":"click","in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"buy-now"},{"actor":"two","do":"wait","ms":2000},{"actor":"two","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"two","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"two","contains":"Desk Lamp","count":1,"do":"expect","testid":"order-item"},{"absent":true,"actor":"two","contains":"Coffee Grinder","do":"expect","testid":"order-item"}]}],"id":106,"setup":[{"actor":"one","do":"signUp","name":"quin"},{"actor":"two","do":"signUp","name":"ros"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","requiresFeatures":["ecommerce.feature.purchasing"],"role":"guarantee","source":"scenarios/01-order-ownership.json"}],"id":"selected-source-020","scenario":{"level":1,"writeUrlPattern":"\\/api\\/|\\/items|\\/cart|\\/orders|\\/checkout|\\/buy|\\/reviews|\\/stock|\\/restock|\\/warehouses"},"source":"scenarios/01-order-ownership.json"},{"checkGroups":[{"checkGroupId":"purchase-attribution","feature":{"actors":["victim","attacker"],"criteria":[{"id":"102a","steps":[{"action":"buy","actor":"attacker","do":"callAction","input":{"attribute":"data-buy-input","contains":"Desk Lamp","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"},"settleMs":2000},{"actor":"attacker","do":"expectActionOutcome","outcome":"accepted"},{"actor":"victim","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"victim","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"victim","contains":"Coffee Grinder","count":1,"do":"expect","testid":"order-item"},{"absent":true,"actor":"victim","contains":"Desk Lamp","do":"expect","testid":"order-item"},{"actor":"attacker","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"attacker","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"attacker","contains":"Desk Lamp","count":1,"do":"expect","testid":"order-item"}]}],"id":102,"setup":[{"actor":"victim","do":"signUp","name":"lee"},{"actor":"attacker","do":"signUp","name":"mel"},{"actor":"victim","do":"click","in":{"contains":"Coffee Grinder","testid":"item-card"},"testid":"buy-now"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","requiresFeatures":["ecommerce.feature.purchasing"],"role":"guarantee","source":"scenarios/01-purchase-attribution.json"}],"id":"selected-source-021","scenario":{"level":1,"writeUrlPattern":null},"source":"scenarios/01-purchase-attribution.json"},{"checkGroups":[{"checkGroupId":"purchase-session","feature":{"actors":["buyer","guest"],"criteria":[{"id":"101a","steps":[{"action":"buy","actor":"guest","authentication":"none","do":"callAction","from":"buyer","input":{"attribute":"data-buy-input","contains":"Bluetooth Speaker","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"},"settleMs":2000},{"actor":"guest","do":"expectActionOutcome","outcome":"refused","routeProvenBy":"buyer"},{"do":"dbExpectStock","item":"Bluetooth Speaker","plus":-1,"relativeTo":"speaker-before-control"}]}],"id":101,"setup":[{"actor":"buyer","do":"signUp","name":"kim"},{"as":"speaker-before-control","do":"dbRecordStock","item":"Bluetooth Speaker"},{"action":"buy","actor":"buyer","do":"callAction","input":{"attribute":"data-buy-input","contains":"Bluetooth Speaker","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"},"settleMs":2000},{"actor":"buyer","do":"expectActionOutcome","outcome":"accepted"},{"do":"dbExpectStock","item":"Bluetooth Speaker","plus":-1,"relativeTo":"speaker-before-control"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","requiresFeatures":["ecommerce.feature.purchasing"],"role":"guarantee","source":"scenarios/01-purchase-session.json"}],"id":"selected-source-022","scenario":{"level":1,"writeUrlPattern":null},"source":"scenarios/01-purchase-session.json"},{"checkGroups":[{"checkGroupId":"restock-race","feature":{"actors":["admin","a","b","c"],"criteria":[{"id":"202-control","steps":[{"do":"dbExpectStock","item":"Bluetooth Speaker","plus":5,"relativeTo":"stored-before-control"},{"actor":"a","do":"expectNumber","in":{"contains":"Bluetooth Speaker","testid":"item-card"},"plus":5,"relativeTo":"storefront-before","testid":"item-stock","within":8000}]},{"id":"202a","steps":[{"as":"stored-before-rush","do":"dbRecordStock","item":"Bluetooth Speaker"},{"actor":"admin","do":"fill","in":{"contains":"Bluetooth Speaker","testid":"admin-location-row"},"testid":"restock-input","text":"5"},{"actor":"a","as":"rush-before","do":"recordNumber","in":{"contains":"Bluetooth Speaker","testid":"item-card"},"testid":"item-stock"},{"branches":[[{"actors":["a","b","c"],"do":"clickConcurrently","in":{"contains":"Bluetooth Speaker","testid":"item-card"},"settleMs":500,"testid":"buy-now"}],[{"actor":"admin","do":"click","in":{"contains":"Bluetooth Speaker","testid":"admin-location-row"},"testid":"restock-submit"}]],"do":"race","settleMs":6000},{"do":"dbExpectStock","item":"Bluetooth Speaker","plus":2,"relativeTo":"stored-before-rush"},{"atLeast":0,"do":"dbExpectStock","item":"Bluetooth Speaker","warehouse":"East"},{"atLeast":0,"do":"dbExpectStock","item":"Bluetooth Speaker","warehouse":"West"},{"actor":"a","do":"reload","settleMs":1000},{"actor":"a","do":"click","testid":"catalog-link"},{"actor":"a","do":"expectNumber","in":{"contains":"Bluetooth Speaker","testid":"item-card"},"plus":2,"relativeTo":"rush-before","testid":"item-stock","within":10000},{"actor":"a","do":"ensureSignedIn","name":"r1","readyTestid":"current-user"},{"actor":"a","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"a","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"a","contains":"Bluetooth Speaker","count":2,"do":"expect","testid":"order-item","within":10000},{"actor":"b","do":"reload","settleMs":1000},{"actor":"b","do":"ensureSignedIn","name":"r2","readyTestid":"current-user"},{"actor":"b","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"b","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"b","contains":"Bluetooth Speaker","count":1,"do":"expect","testid":"order-item","within":10000},{"actor":"c","do":"reload","settleMs":1000},{"actor":"c","do":"ensureSignedIn","name":"r3","readyTestid":"current-user"},{"actor":"c","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"c","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"c","contains":"Bluetooth Speaker","count":1,"do":"expect","testid":"order-item","within":10000},{"actor":"admin","do":"reload","settleMs":1000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"admin-link"},{"actor":"admin","do":"expectNumber","in":{"contains":"Bluetooth Speaker","testid":"admin-item-row"},"plus":2,"relativeTo":"stored-before-rush","testid":"admin-stock","within":10000},{"actor":"a","do":"reload","settleMs":1000},{"actor":"a","do":"click","testid":"catalog-link"},{"actor":"a","do":"expectNumber","in":{"contains":"Bluetooth Speaker","testid":"item-card"},"plus":2,"relativeTo":"stored-before-rush","testid":"item-stock","within":10000},{"actor":"a","do":"ensureSignedIn","name":"r1","readyTestid":"current-user"},{"account":"{user:r1}","as":"mixed-a","do":"dbRecordCheckout","item":"Bluetooth Speaker","storage":{"cart":false,"kind":"order-data","warehouses":true}},{"account":"{user:r2}","as":"mixed-b","do":"dbRecordCheckout","item":"Bluetooth Speaker","storage":{"cart":false,"kind":"order-data","warehouses":true}},{"account":"{user:r3}","as":"mixed-c","do":"dbRecordCheckout","item":"Bluetooth Speaker","storage":{"cart":false,"kind":"order-data","warehouses":true}},{"action":"buy","actors":["a","b","c"],"alongside":[{"action":"restock","actors":["admin"],"input":{"attribute":"data-restock-input","contains":"Bluetooth Speaker","testid":"admin-location-row"},"namedAction":{"args":[0,0,1],"id":"restock","params":[{"in":"body","name":"itemId","wireType":"u64"},{"in":"body","name":"warehouseId","wireType":"u64"},{"in":"body","name":"quantity"}],"path":"/api/admin/restock","reducer":"admin_restock"},"requests":1}],"do":"callConcurrently","from":"a","input":{"attribute":"data-buy-input","contains":"Bluetooth Speaker","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"},"requests":3,"settleMs":3000},{"accepted":4,"do":"expectCallOutcomes"},{"before":{"a":"mixed-a","b":"mixed-b","c":"mixed-c"},"do":"dbExpectPurchases","purchases":3}]}],"id":202,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"click","testid":"admin-link"},{"actor":"a","do":"signUp","name":"r1"},{"actor":"b","do":"signUp","name":"r2"},{"actor":"c","do":"signUp","name":"r3"},{"as":"stored-before-serial-purchase","do":"dbRecordStock","item":"Bluetooth Speaker"},{"actor":"a","do":"click","in":{"contains":"Bluetooth Speaker","testid":"item-card"},"testid":"buy-now"},{"actor":"a","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"a","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"a","contains":"Bluetooth Speaker","count":1,"do":"expect","testid":"order-item","within":10000},{"do":"dbExpectStock","item":"Bluetooth Speaker","plus":-1,"relativeTo":"stored-before-serial-purchase"},{"actor":"a","do":"reload","settleMs":1000},{"actor":"a","do":"ensureSignedIn","name":"r1","readyTestid":"current-user"},{"actor":"admin","do":"reload","settleMs":1000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","testid":"admin-link"},{"actor":"admin","do":"expectNumber","in":{"contains":"Bluetooth Speaker","testid":"admin-item-row"},"plus":-1,"relativeTo":"stored-before-serial-purchase","testid":"admin-stock","within":10000},{"as":"stored-before-control","do":"dbRecordStock","item":"Bluetooth Speaker"},{"actor":"admin","as":"warehouse-before","do":"recordNumber","in":{"contains":"Bluetooth Speaker","testid":"admin-location-row"},"testid":"admin-location-qty"},{"actor":"a","do":"click","testid":"catalog-link"},{"actor":"a","as":"storefront-before","do":"recordNumber","in":{"contains":"Bluetooth Speaker","testid":"item-card"},"testid":"item-stock"},{"actor":"admin","do":"fill","in":{"contains":"Bluetooth Speaker","testid":"admin-location-row"},"testid":"restock-input","text":"5"},{"actor":"admin","do":"click","in":{"contains":"Bluetooth Speaker","testid":"admin-location-row"},"testid":"restock-submit"},{"do":"dbExpectStock","item":"Bluetooth Speaker","plus":5,"relativeTo":"stored-before-control","within":8000},{"actor":"admin","do":"reload","settleMs":1000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","testid":"admin-link"},{"actor":"admin","do":"expectNumber","in":{"contains":"Bluetooth Speaker","testid":"admin-location-row"},"plus":5,"relativeTo":"warehouse-before","testid":"admin-location-qty","within":8000},{"actor":"a","do":"reload","settleMs":1000},{"actor":"a","do":"click","testid":"catalog-link"},{"actor":"a","do":"expectNumber","in":{"contains":"Bluetooth Speaker","testid":"item-card"},"plus":5,"relativeTo":"storefront-before","testid":"item-stock","within":8000},{"do":"dbExpectStock","item":"Bluetooth Speaker","plus":5,"relativeTo":"stored-before-control"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.concurrency-safety","requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.warehouse-admin"],"role":"guarantee","source":"scenarios/01-restock-race.json"}],"id":"selected-source-023","scenario":{"level":1,"writeUrlPattern":"\\/api\\/|\\/items|\\/cart|\\/orders|\\/checkout|\\/buy|\\/reviews|\\/stock|\\/restock|\\/warehouses"},"source":"scenarios/01-restock-race.json"},{"checkGroups":[{"checkGroupId":"review-eligibility","feature":{"actors":["owner","stranger"],"criteria":[{"id":"108a","steps":[{"action":"buy","actor":"owner","do":"callAction","input":{"attribute":"data-buy-input","contains":"Air Purifier","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"}},{"actor":"owner","do":"expectActionOutcome","outcome":"accepted"},{"actor":"owner","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"owner","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"owner","contains":"Air Purifier","do":"expect","testid":"order-item"},{"actor":"owner","do":"click","ifAvailable":true,"testid":"overlay-close"},{"actor":"owner","do":"click","ifAvailable":true,"testid":"catalog-link"},{"action":"submitReview","actor":"owner","do":"callAction","from":"owner","input":{"attribute":"data-buy-input","contains":"Air Purifier","testid":"item-card"},"namedAction":{"args":[0,4,"eligible review control"],"id":"submitReview","method":"POST","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"},{"in":"body","name":"rating"},{"in":"body","name":"comment"}],"path":"/api/items/:id/reviews","reducer":"submit_review"},"settleMs":1500},{"actor":"owner","do":"expectActionOutcome","outcome":"accepted"},{"actor":"stranger","do":"openItem","item":"Air Purifier"},{"actor":"stranger","contains":"eligible review control","do":"expect","testid":"review-item"},{"action":"submitReview","actor":"stranger","do":"callAction","from":"owner","input":{"attribute":"data-buy-input","contains":"Air Purifier","testid":"item-card"},"namedAction":{"args":[0,4,"never bought this"],"id":"submitReview","method":"POST","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"},{"in":"body","name":"rating"},{"in":"body","name":"comment"}],"path":"/api/items/:id/reviews","reducer":"submit_review"},"settleMs":1500},{"actor":"stranger","do":"expectActionOutcome","outcome":"application-refused","routeProvenBy":"owner"},{"actor":"stranger","do":"reload","settleMs":1500},{"actor":"stranger","do":"ensureSignedIn","name":"uma","readyTestid":"current-user"},{"actor":"stranger","do":"click","ifAvailable":true,"testid":"overlay-close"},{"actor":"stranger","do":"click","ifAvailable":true,"testid":"catalog-link"},{"actor":"stranger","do":"openItem","item":"Air Purifier"},{"actor":"stranger","contains":"eligible review control","do":"expect","testid":"review-item"},{"absent":true,"actor":"stranger","contains":"never bought this","do":"expect","testid":"review-item"}]},{"id":"108b","steps":[{"action":"buy","actor":"owner","do":"callAction","input":{"attribute":"data-buy-input","contains":"Keyboard","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"}},{"actor":"owner","do":"expectActionOutcome","outcome":"accepted"},{"actor":"owner","do":"openItem","item":"Keyboard"},{"actor":"owner","do":"click","ifAvailable":true,"testid":"review-toggle","unlessVisible":"review-rating"},{"actor":"owner","do":"fill","testid":"review-rating","text":"4"},{"actor":"owner","do":"fill","testid":"review-input","text":"bought and used it"},{"actor":"owner","do":"click","testid":"review-submit"},{"actor":"owner","contains":"bought and used it","do":"expect","testid":"review-item","within":8000}]}],"id":108,"setup":[{"actor":"owner","do":"signUp","name":"tam"},{"actor":"stranger","do":"signUp","name":"uma"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.reviews"],"role":"guarantee","source":"scenarios/01-review-eligibility.json"}],"id":"selected-source-024","scenario":{"level":1,"writeUrlPattern":"\\/api\\/|\\/items|\\/cart|\\/orders|\\/checkout|\\/buy|\\/reviews|\\/stock|\\/restock|\\/warehouses"},"source":"scenarios/01-review-eligibility.json"},{"checkGroups":[{"checkGroupId":"rating","feature":{"actors":["author","other"],"criteria":[{"id":"6c","steps":[{"actor":"other","do":"openItem","item":"Gaming Mouse"},{"actor":"other","do":"click","ifAvailable":true,"testid":"review-toggle","unlessVisible":"review-rating"},{"actor":"other","do":"fill","testid":"review-rating","text":"4"},{"actor":"other","do":"fill","testid":"review-input","text":"does the job"},{"actor":"other","do":"click","testid":"review-submit"},{"actor":"other","do":"expectNumber","equals":3,"testid":"review-average","within":10000},{"actors":["author","other"],"do":"expectAgreement","numeric":true,"testid":"review-average","within":10000}]}],"id":6,"setup":[{"actor":"author","do":"signUp","name":"leon"},{"actor":"other","do":"signUp","name":"maya"},{"action":"buy","actor":"author","do":"callAction","input":{"attribute":"data-buy-input","contains":"Gaming Mouse","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"}},{"actor":"author","do":"expectActionOutcome","outcome":"accepted"},{"actor":"author","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"author","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"author","contains":"Gaming Mouse","do":"expect","testid":"order-item","within":10000},{"actor":"author","do":"click","ifAvailable":true,"testid":"overlay-close"},{"actor":"author","do":"click","ifAvailable":true,"testid":"catalog-link"},{"actor":"author","do":"openItem","item":"Gaming Mouse"},{"actor":"author","do":"click","ifAvailable":true,"testid":"review-toggle","unlessVisible":"review-rating"},{"actor":"author","do":"fill","testid":"review-rating","text":"2"},{"actor":"author","do":"fill","testid":"review-input","text":"works for travel"},{"actor":"author","do":"click","testid":"review-submit"},{"actor":"author","contains":"works for travel","do":"expect","testid":"review-item"},{"action":"buy","actor":"other","do":"callAction","input":{"attribute":"data-buy-input","contains":"Gaming Mouse","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"}},{"actor":"other","do":"expectActionOutcome","outcome":"accepted"},{"actor":"other","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"other","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"other","contains":"Gaming Mouse","do":"expect","testid":"order-item","within":10000},{"actor":"other","do":"click","ifAvailable":true,"testid":"overlay-close"},{"actor":"other","do":"click","ifAvailable":true,"testid":"catalog-link"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.live-state","requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.reviews"],"role":"guarantee","source":"scenarios/01-review-rating-live.json"}],"id":"selected-source-025","scenario":{"level":1,"writeUrlPattern":null},"source":"scenarios/01-review-rating-live.json"},{"checkGroups":[{"checkGroupId":"unique-review","feature":{"actors":["author"],"criteria":[{"id":"6b","steps":[{"actor":"author","do":"click","ifAvailable":true,"testid":"overlay-close"},{"actor":"author","do":"click","ifAvailable":true,"testid":"catalog-link"},{"action":"submitReview","actor":"author","do":"callAction","from":"author","input":{"attribute":"data-buy-input","contains":"Air Purifier","testid":"item-card"},"namedAction":{"args":[0,4,"changed my mind"],"id":"submitReview","method":"POST","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"},{"in":"body","name":"rating"},{"in":"body","name":"comment"}],"path":"/api/items/:id/reviews","reducer":"submit_review"},"settleMs":1500},{"actor":"author","do":"expectActionOutcome","outcome":"completed"},{"actor":"author","do":"reload","settleMs":2500},{"actor":"author","do":"ensureSignedIn","name":"kira","readyTestid":"current-user"},{"actor":"author","do":"click","ifAvailable":true,"testid":"overlay-close"},{"actor":"author","do":"click","ifAvailable":true,"testid":"catalog-link"},{"actor":"author","do":"openItem","item":"Air Purifier"},{"actor":"author","count":1,"do":"expect","testid":"review-item","within":10000}]}],"id":6,"setup":[{"actor":"author","do":"signUp","name":"kira"},{"action":"buy","actor":"author","do":"callAction","input":{"attribute":"data-buy-input","contains":"Air Purifier","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"}},{"actor":"author","do":"expectActionOutcome","outcome":"accepted"},{"actor":"author","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"author","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"author","contains":"Air Purifier","do":"expect","testid":"order-item","within":10000},{"actor":"author","do":"click","ifAvailable":true,"testid":"overlay-close"},{"actor":"author","do":"click","ifAvailable":true,"testid":"catalog-link"},{"actor":"author","do":"openItem","item":"Air Purifier"},{"actor":"author","do":"click","ifAvailable":true,"testid":"review-toggle","unlessVisible":"review-rating"},{"actor":"author","do":"fill","testid":"review-rating","text":"4"},{"actor":"author","do":"fill","testid":"review-input","text":"quiet and effective"},{"actor":"author","do":"click","testid":"review-submit"},{"actor":"author","contains":"quiet and effective","do":"expect","testid":"review-item"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.transactional-integrity","requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.reviews"],"role":"guarantee","source":"scenarios/01-review-uniqueness.json"}],"id":"selected-source-026","scenario":{"level":1,"writeUrlPattern":null},"source":"scenarios/01-review-uniqueness.json"},{"checkGroups":[{"checkGroupId":"reviews","feature":{"actors":["author","visitor"],"criteria":[{"id":"6a","steps":[{"actor":"author","do":"openItem","item":"Induction Cooktop"},{"actor":"author","do":"click","ifAvailable":true,"testid":"review-toggle","unlessVisible":"review-rating"},{"actor":"author","do":"fill","testid":"review-rating","text":"4"},{"actor":"author","do":"fill","testid":"review-input","text":"solid mold"},{"actor":"author","do":"click","testid":"review-submit"},{"actor":"author","contains":"solid mold","do":"expect","testid":"review-item"},{"actor":"visitor","do":"openItem","item":"Induction Cooktop"},{"actor":"visitor","contains":"solid mold","do":"expect","testid":"review-item","within":10000}]}],"id":6,"setup":[{"actor":"author","do":"signUp","name":"hal"},{"actor":"author","do":"click","in":{"contains":"Induction Cooktop","testid":"item-card"},"testid":"buy-now"},{"actor":"author","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"author","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"author","contains":"Induction Cooktop","do":"expect","testid":"order-item","within":10000},{"actor":"author","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"author","do":"click","ifAvailable":true,"testid":"catalog-link"}]},"packId":"ecommerce.feature.reviews","role":"feature","source":"scenarios/01-review-visibility.json"}],"id":"selected-source-027","scenario":{"level":1,"writeUrlPattern":null},"source":"scenarios/01-review-visibility.json"},{"checkGroups":[{"checkGroupId":"server-price","feature":{"actors":["buyer"],"criteria":[{"id":"104a","steps":[{"action":"buy","actor":"buyer","do":"callAction","input":{"attribute":"data-buy-input","contains":"Espresso Machine","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"},"settleMs":2000},{"actor":"buyer","do":"expectActionOutcome","outcome":"accepted"},{"action":"buy","actor":"buyer","do":"callAction","input":{"attribute":"data-buy-input","contains":"Coffee Grinder","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"},"settleMs":2000},{"actor":"buyer","do":"expectActionOutcome","outcome":"accepted"},{"actor":"buyer","do":"freshClient"},{"actor":"buyer-fresh","do":"signIn","name":"oli"},{"actor":"buyer-fresh","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"buyer-fresh","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"buyer-fresh","count":2,"do":"expect","testid":"order-item"},{"actor":"buyer-fresh","contains":"Espresso Machine","count":1,"do":"expect","testid":"order-item"},{"actor":"buyer-fresh","do":"expectNumber","equals":449,"in":{"contains":"Espresso Machine","testid":"order-item"},"testid":"order-total"},{"actor":"buyer-fresh","contains":"Coffee Grinder","count":1,"do":"expect","testid":"order-item"},{"actor":"buyer-fresh","do":"expectNumber","equals":64,"in":{"contains":"Coffee Grinder","testid":"order-item"},"testid":"order-total"}]}],"id":104,"setup":[{"actor":"buyer","do":"signUp","name":"oli"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.transactional-integrity","requiresFeatures":["ecommerce.feature.purchasing"],"role":"guarantee","source":"scenarios/01-server-price.json"}],"id":"selected-source-028","scenario":{"level":1,"writeUrlPattern":null},"source":"scenarios/01-server-price.json"},{"checkGroups":[{"checkGroupId":"warehouse-area-boundary","feature":{"actors":["admin","staff"],"criteria":[{"id":"7a","steps":[{"actor":"admin","do":"expect","testid":"admin-item-row"},{"actor":"staff","do":"click","ifAvailable":true,"settleMs":1500,"testid":"admin-link"},{"absent":true,"actor":"staff","do":"expect","testid":"admin-item-row"}]}],"id":7,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"admin","do":"click","testid":"admin-link"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","requiresFeatures":["ecommerce.feature.warehouse-admin"],"role":"guarantee","source":"scenarios/01-warehouse-admin-staff.json"},{"checkGroupId":"warehouse-view","feature":{"actors":["admin","staff"],"criteria":[{"id":"7b","steps":[{"actor":"admin","count":13,"do":"expect","testid":"admin-item-row"},{"actor":"admin","count":26,"do":"expect","testid":"admin-location-row"},{"actor":"admin","contains":"East","do":"expect","testid":"admin-warehouse-item"},{"actor":"admin","contains":"West","do":"expect","testid":"admin-warehouse-item"},{"actor":"admin","do":"expectNumber","equals":100,"in":{"contains":"Gaming Mouse","testid":"admin-item-row"},"testid":"admin-stock"}]}],"id":7,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"admin","do":"click","testid":"admin-link"}]},"packId":"ecommerce.feature.warehouse-admin","role":"feature","source":"scenarios/01-warehouse-admin-staff.json"}],"id":"selected-source-029","scenario":{"level":1,"writeUrlPattern":null},"source":"scenarios/01-warehouse-admin-staff.json"},{"checkGroups":[{"checkGroupId":"warehouse-stock","feature":{"actors":["admin","visitor"],"criteria":[{"id":"7c","steps":[{"actor":"admin","do":"fill","in":{"contains":"Gaming Mouse","testid":"admin-location-row"},"testid":"restock-input","text":"25"},{"actor":"admin","do":"click","in":{"contains":"Gaming Mouse","testid":"admin-location-row"},"testid":"restock-submit"},{"actor":"visitor","do":"expectNumber","equals":125,"in":{"contains":"Gaming Mouse","testid":"item-card"},"testid":"item-stock","within":10000},{"actor":"admin","do":"expectNumber","equals":125,"in":{"contains":"Gaming Mouse","testid":"admin-item-row"},"testid":"admin-stock"}]}],"id":7,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"click","testid":"admin-link"},{"actor":"visitor","do":"expectNumber","equals":100,"in":{"contains":"Gaming Mouse","testid":"item-card"},"testid":"item-stock"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.live-state","requiresFeatures":["ecommerce.feature.catalog-items","ecommerce.feature.warehouse-admin"],"role":"guarantee","source":"scenarios/01-warehouse-stock-live-staff.json"}],"id":"selected-source-030","scenario":{"level":1,"writeUrlPattern":null},"source":"scenarios/01-warehouse-stock-live-staff.json"},{"checkGroups":[{"checkGroupId":"cancellation-and-return","feature":{"actors":["customer","staff"],"criteria":[{"id":"3d","steps":[{"actor":"customer","do":"click","in":{"contains":"Coffee Grinder","testid":"item-card"},"testid":"buy-now"},{"actor":"staff","contains":"Coffee Grinder","do":"expect","testid":"queue-item","within":10000},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"customer","do":"click","testid":"orders-toggle"},{"actor":"customer","do":"click","in":{"contains":"Coffee Grinder","testid":"order-item"},"testid":"cancel-order"},{"actor":"staff","contains":"Coffee Grinder","do":"waitUntilAbsent","testid":"queue-item","within":10000}]}],"id":3,"setup":[{"actor":"customer","do":"signUp","name":"cancel-queue"},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"staff","do":"click","testid":"staff-link"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.progression.cancellation-queue-specifications","requiresFeatures":["ecommerce.l2.order-cancellation-features","ecommerce.progression.fulfilment-queue"],"role":"guarantee","source":"scenarios/02-cancellation-queue.json","stablePackId":"ecommerce.returns-pricing"}],"id":"selected-source-031","scenario":{"level":2,"writeUrlPattern":null},"source":"scenarios/02-cancellation-queue.json"},{"checkGroups":[{"checkGroupId":"fulfilment-area-boundary","feature":{"actors":["customer","staff","admin"],"criteria":[{"id":"1d","steps":[{"actor":"staff","do":"click","testid":"staff-link"},{"actor":"staff","do":"expect","testid":"fulfilment-panel"},{"actor":"admin","do":"click","testid":"staff-link"},{"actor":"admin","do":"expect","testid":"fulfilment-panel"},{"actor":"customer","do":"click","ifAvailable":true,"settleMs":1500,"testid":"staff-link"},{"absent":true,"actor":"customer","do":"expect","testid":"fulfilment-panel"}]}],"id":1,"setup":[{"actor":"customer","do":"signUp","name":"fq-customer"},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","requiresFeatures":["ecommerce.progression.fulfilment-queue"],"role":"guarantee","source":"scenarios/02-fulfilment-access.json"}],"id":"selected-source-032","scenario":{"level":2,"writeUrlPattern":null},"source":"scenarios/02-fulfilment-access.json"},{"checkGroups":[{"checkGroupId":"fulfilment-queue","feature":{"actors":["customer","staff"],"criteria":[{"id":"1a","steps":[{"actor":"staff","as":"depth-before","do":"recordNumber","testid":"queue-depth"},{"actor":"customer","do":"click","in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"buy-now"},{"actor":"staff","contains":"Desk Lamp","do":"expect","testid":"queue-item","within":10000},{"actor":"staff","do":"expectNumber","plus":1,"relativeTo":"depth-before","testid":"queue-depth"}]}],"id":1,"setup":[{"actor":"customer","do":"signUp","name":"fq-live"},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"staff","do":"click","testid":"staff-link"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.live-state","requiresFeatures":["ecommerce.progression.fulfilment-queue"],"role":"guarantee","source":"scenarios/02-fulfilment-live.json"}],"id":"selected-source-033","scenario":{"level":2,"writeUrlPattern":null},"source":"scenarios/02-fulfilment-live.json"},{"checkGroups":[{"checkGroupId":"fulfilment-queue","feature":{"actors":["customer","staff"],"criteria":[{"id":"1c","steps":[{"action":"buy","actor":"customer","do":"callAction","input":{"attribute":"data-buy-input","contains":"Keyboard","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"}},{"actor":"customer","do":"expectActionOutcome","outcome":"accepted"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"customer","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"customer","do":"expect","ignoreCase":true,"in":{"contains":"Keyboard","testid":"order-item"},"testid":"order-status","value":"pending","within":10000},{"actor":"staff","do":"reload","settleMs":2000},{"actor":"staff","do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026","readyTestid":"current-user"},{"actor":"staff","do":"click","ifAvailable":true,"testid":"staff-link"},{"actor":"staff","contains":"Keyboard","do":"expect","testid":"queue-item","within":10000},{"actor":"staff","do":"click","in":{"contains":"Keyboard","testid":"queue-item"},"testid":"ship-submit"},{"actor":"staff","attribute":"data-submit-state","do":"expect","testid":"fulfilment-panel","value":"succeeded","within":10000},{"actor":"staff","do":"reload","settleMs":2000},{"actor":"staff","do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026","readyTestid":"current-user"},{"actor":"staff","do":"click","ifAvailable":true,"testid":"staff-link"},{"absent":true,"actor":"staff","contains":"Keyboard","do":"expect","testid":"queue-item","within":10000},{"actor":"customer","do":"reload","settleMs":2000},{"actor":"customer","do":"ensureSignedIn","name":"fq-ship","readyTestid":"current-user"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"customer","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"customer","do":"expect","ignoreCase":true,"in":{"contains":"Keyboard","testid":"order-item"},"testid":"order-status","value":"shipped","within":10000}]}],"id":1,"setup":[{"actor":"customer","do":"signUp","name":"fq-ship"},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"staff","do":"click","testid":"staff-link"}]},"packId":"ecommerce.progression.fulfilment-queue","requiresFeatures":["ecommerce.feature.purchasing"],"role":"feature","source":"scenarios/02-fulfilment-ship.json","stablePackId":"ecommerce.operations-access"}],"id":"selected-source-034","scenario":{"level":2,"writeUrlPattern":null},"source":"scenarios/02-fulfilment-ship.json"},{"checkGroups":[{"checkGroupId":"refund-accounting","feature":{"actors":["admin","customer","customer2"],"criteria":[{"id":"203a","steps":[{"actor":"admin","as":"rev-start","do":"recordNumber","testid":"admin-revenue"},{"actor":"customer","do":"click","in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"buy-now"},{"actor":"customer","do":"wait","ms":2500},{"actor":"admin","do":"reload","settleMs":1000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"admin","do":"click","testid":"admin-link","unlessVisible":"admin-revenue"},{"actor":"admin","do":"expectNumber","plus":42,"relativeTo":"rev-start","testid":"admin-revenue","within":10000},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"customer","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"customer","do":"expect","ignoreCase":true,"in":{"contains":"Desk Lamp","testid":"order-item"},"testid":"order-status","value":"pending","within":10000},{"account":"{user:books}","as":"cancel-before","do":"dbRecordCheckout","item":"Desk Lamp","storage":{"cart":false,"kind":"order-data","warehouses":true}},{"action":"cancel","actors":["customer","customer2"],"do":"callConcurrently","from":"customer","input":{"attribute":"data-cancel-input","contains":"Desk Lamp","testid":"order-item"},"namedAction":{"args":[0],"id":"cancel","params":[{"in":"path","name":"orderId","placeholder":":id","wireType":"u64"}],"path":"/api/orders/:id/cancel","reducer":"cancel_order"},"requests":4,"settleMs":3000},{"do":"expectCallOutcomes"},{"before":"cancel-before","do":"dbExpectCancellation"},{"actor":"admin","do":"reload","settleMs":1000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"admin","do":"click","testid":"admin-link","unlessVisible":"admin-revenue"},{"actor":"admin","do":"expectNumber","plus":0,"relativeTo":"rev-start","testid":"admin-revenue","within":10000}]}],"id":203,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"customer","do":"signUp","name":"books"},{"actor":"customer2","do":"signIn","name":"books"},{"actor":"admin","do":"click","testid":"admin-link"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.progression.cancellation-accounting-specifications","requiresFeatures":["ecommerce.l2.order-cancellation-features"],"role":"guarantee","source":"scenarios/02-invariants.json","stablePackId":"ecommerce.returns-pricing"},{"checkGroupId":"refund-accounting","feature":{"actors":["admin","customer","customer2"],"criteria":[{"id":"203b","steps":[{"actor":"admin","as":"history-revenue-before-sale","do":"recordNumber","testid":"admin-revenue"},{"actor":"customer","do":"pressKey","key":"Escape"},{"actor":"customer","do":"click","in":{"contains":"Bluetooth Speaker","testid":"item-card"},"testid":"buy-now"},{"actor":"customer","do":"wait","ms":2500},{"actor":"admin","do":"reload","settleMs":1000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"admin","do":"click","testid":"admin-link","unlessVisible":"admin-revenue"},{"actor":"admin","do":"expectNumber","plus":79.5,"relativeTo":"history-revenue-before-sale","testid":"admin-revenue","within":10000},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"customer","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"customer","contains":"Bluetooth Speaker","count":1,"do":"expect","testid":"order-item","within":10000},{"actor":"admin","as":"rev-after-sale","do":"recordNumber","testid":"admin-revenue"},{"actor":"admin","do":"fill","in":{"contains":"Bluetooth Speaker","testid":"admin-item-row"},"testid":"price-input","text":"5.00"},{"actor":"admin","do":"click","in":{"contains":"Bluetooth Speaker","testid":"admin-item-row"},"testid":"price-submit"},{"actor":"admin","do":"wait","ms":3000},{"actor":"admin","do":"reload","settleMs":2000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"admin-link","within":1000},{"actor":"admin","do":"expectNumber","equals":5,"in":{"contains":"Bluetooth Speaker","testid":"admin-item-row"},"testid":"price-input","within":10000},{"actor":"admin","do":"reload","settleMs":1000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"admin","do":"click","testid":"admin-link","unlessVisible":"admin-revenue"},{"actor":"admin","do":"expectNumber","plus":0,"relativeTo":"rev-after-sale","testid":"admin-revenue"}]}],"id":203,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"customer","do":"signUp","name":"books"},{"actor":"customer2","do":"signIn","name":"books"},{"actor":"admin","do":"click","testid":"admin-link"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.progression.price-accounting-specifications","requiresFeatures":["ecommerce.l2.price-history-features"],"role":"guarantee","source":"scenarios/02-invariants.json","stablePackId":"ecommerce.returns-pricing"}],"id":"selected-source-035","scenario":{"level":2,"writeUrlPattern":"\\/api\\/|\\/items|\\/cart|\\/orders|\\/checkout|\\/buy|\\/reviews|\\/stock|\\/restock|\\/warehouses|\\/transfer|\\/cancel|\\/return|\\/ship|\\/price|\\/fulfil"},"source":"scenarios/02-invariants.json"},{"checkGroups":[{"checkGroupId":"price-history","feature":{"actors":["admin","visitor"],"criteria":[{"id":"4b","steps":[{"actor":"visitor","atLeast":2,"do":"expectNumber","in":{"contains":"Air Purifier","testid":"item-card"},"testid":"item-price"},{"actor":"admin","do":"fill","in":{"contains":"Air Purifier","testid":"admin-item-row"},"testid":"price-input","text":"1.00"},{"actor":"admin","do":"click","in":{"contains":"Air Purifier","testid":"admin-item-row"},"testid":"price-submit"},{"actor":"visitor","do":"expectNumber","equals":1,"in":{"contains":"Air Purifier","testid":"item-card"},"testid":"item-price","within":10000}]}],"id":4,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"click","testid":"admin-link"},{"actor":"visitor","do":"fill","enter":true,"settleMs":1500,"testid":"search-input","text":"Air Purifier"}]},"packId":"ecommerce.l2.price-history-features","role":"feature","source":"scenarios/02-live-price.json","stablePackId":"ecommerce.returns-pricing"}],"id":"selected-source-036","scenario":{"level":2,"writeUrlPattern":null},"source":"scenarios/02-live-price.json"},{"checkGroups":[{"checkGroupId":"operational-views","feature":{"actors":["admin","customer","restocker"],"criteria":[{"id":"5e","steps":[{"actor":"admin","contains":"Air Purifier","do":"expect","testid":"low-stock-item","within":8000}]}],"id":5,"setup":[{"do":"dbSetStock","item":"Air Purifier","quantity":2,"settleMs":250,"warehouse":"East"},{"do":"dbSetStock","item":"Air Purifier","quantity":1,"settleMs":250,"warehouse":"West"},{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"customer","do":"signUp","name":"low-stock-focused"},{"actor":"admin","do":"reload","settleMs":1000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"customer","do":"reload","settleMs":1000},{"actor":"customer","do":"ensureSignedIn","name":"low-stock-focused","readyTestid":"current-user"},{"actor":"admin","do":"click","testid":"admin-link"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"low-stock-link","unlessVisible":"low-stock-item","within":10000}]},"packId":"ecommerce.l2.inventory-dashboard","role":"feature","source":"scenarios/02-low-stock.json","stablePackId":"ecommerce.inventory-operations"},{"checkGroupId":"inventory-dashboard","feature":{"actors":["admin","customer","restocker"],"criteria":[{"id":"5a","steps":[{"actor":"admin","contains":"Air Purifier","do":"expect","testid":"low-stock-item","within":8000},{"actor":"restocker","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"restocker","do":"click","testid":"admin-link"},{"actor":"restocker","do":"fill","in":{"contains":"Air Purifier","testid":"admin-location-row"},"testid":"restock-input","text":"8"},{"actor":"restocker","do":"click","in":{"contains":"Air Purifier","testid":"admin-location-row"},"testid":"restock-submit"},{"actor":"admin","contains":"Air Purifier","do":"waitUntilAbsent","testid":"low-stock-item","within":10000},{"actor":"customer","do":"click","in":{"contains":"Air Purifier","testid":"item-card"},"testid":"buy-now"},{"actor":"admin","contains":"Air Purifier","do":"expect","testid":"low-stock-item","within":10000}]}],"id":5,"setup":[{"do":"dbSetStock","item":"Air Purifier","quantity":2,"settleMs":250,"warehouse":"East"},{"do":"dbSetStock","item":"Air Purifier","quantity":1,"settleMs":250,"warehouse":"West"},{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"customer","do":"signUp","name":"low-stock-focused"},{"actor":"admin","do":"reload","settleMs":1000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"customer","do":"reload","settleMs":1000},{"actor":"customer","do":"ensureSignedIn","name":"low-stock-focused","readyTestid":"current-user"},{"actor":"admin","do":"click","testid":"admin-link"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"low-stock-link","unlessVisible":"low-stock-item","within":10000}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.live-state","requiresFeatures":["ecommerce.feature.purchasing","ecommerce.l2.inventory-dashboard"],"role":"guarantee","source":"scenarios/02-low-stock.json"}],"id":"selected-source-037","scenario":{"level":2,"writeUrlPattern":null},"source":"scenarios/02-low-stock.json"},{"checkGroups":[{"checkGroupId":"operational-views","feature":{"actors":["buyer","visitor"],"criteria":[{"id":"5d","steps":[{"actor":"visitor","do":"reload","settleMs":2500},{"actor":"visitor","do":"expectNumber","equals":1,"in":{"contains":"Gaming Mouse","testid":"recommended-item"},"testid":"recommendation-rank","within":10000}]}],"id":5,"setup":[{"actor":"buyer","do":"signUp","name":"best-seller-buyer"},{"actor":"buyer","do":"click","in":{"contains":"Gaming Mouse","testid":"item-card"},"testid":"buy-now"},{"actor":"buyer","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"buyer","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"buyer","contains":"Gaming Mouse","do":"expect","testid":"order-item","within":10000}]},"packId":"ecommerce.l2.sales-dashboard","role":"feature","source":"scenarios/02-operational-best-sellers.json","stablePackId":"ecommerce.inventory-operations"}],"id":"selected-source-038","scenario":{"level":2,"writeUrlPattern":null},"source":"scenarios/02-operational-best-sellers.json"},{"checkGroups":[{"checkGroupId":"operational-views","feature":{"actors":["admin","customer"],"criteria":[{"id":"5f","steps":[{"actor":"admin","do":"click","ifAvailable":true,"testid":"sales-link","unlessVisible":"category-row"},{"actor":"admin","as":"audio-core-units","do":"recordNumber","in":{"contains":"Audio","testid":"category-row"},"testid":"category-units"},{"actor":"admin","as":"audio-core-revenue","do":"recordNumber","in":{"contains":"Audio","testid":"category-row"},"testid":"category-revenue"},{"actor":"customer","do":"click","in":{"contains":"Bluetooth Speaker","testid":"item-card"},"testid":"buy-now"},{"actor":"admin","do":"reload","settleMs":2000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","testid":"admin-link"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"sales-link","unlessVisible":"category-row"},{"actor":"admin","do":"expectNumber","in":{"contains":"Audio","testid":"category-row"},"plus":1,"relativeTo":"audio-core-units","testid":"category-units"},{"actor":"admin","do":"expectNumber","in":{"contains":"Audio","testid":"category-row"},"plus":79.5,"relativeTo":"audio-core-revenue","testid":"category-revenue"}]}],"id":5,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"customer","do":"signUp","name":"category-totals"},{"actor":"admin","do":"click","testid":"admin-link"}]},"packId":"ecommerce.l2.sales-dashboard","role":"feature","source":"scenarios/02-operational-category-totals.json","stablePackId":"ecommerce.inventory-operations"},{"checkGroupId":"sales-dashboard","feature":{"actors":["admin","customer"],"criteria":[{"id":"5b","steps":[{"actor":"admin","do":"click","ifAvailable":true,"testid":"sales-link","unlessVisible":"category-row"},{"actor":"admin","as":"audio-units","do":"recordNumber","in":{"contains":"Audio","testid":"category-row"},"testid":"category-units"},{"actor":"admin","as":"audio-revenue","do":"recordNumber","in":{"contains":"Audio","testid":"category-row"},"testid":"category-revenue"},{"actor":"customer","do":"click","in":{"contains":"Bluetooth Speaker","testid":"item-card"},"testid":"buy-now"},{"actor":"admin","do":"expectNumber","in":{"contains":"Audio","testid":"category-row"},"plus":1,"relativeTo":"audio-units","testid":"category-units","within":10000},{"actor":"admin","do":"expectNumber","in":{"contains":"Audio","testid":"category-row"},"plus":79.5,"relativeTo":"audio-revenue","testid":"category-revenue","within":10000}]}],"id":5,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"customer","do":"signUp","name":"category-totals"},{"actor":"admin","do":"click","testid":"admin-link"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.live-state","requiresFeatures":["ecommerce.feature.purchasing","ecommerce.l2.sales-dashboard"],"role":"guarantee","source":"scenarios/02-operational-category-totals.json"}],"id":"selected-source-039","scenario":{"level":2,"writeUrlPattern":null},"source":"scenarios/02-operational-category-totals.json"},{"checkGroups":[{"checkGroupId":"operational-views","feature":{"actors":["customer"],"criteria":[{"id":"5c","steps":[{"actor":"customer","do":"click","in":{"contains":"Bluetooth Speaker","testid":"item-card"},"testid":"buy-now"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"catalog-link"},{"actor":"customer","contains":"Headphones","do":"expect","in":{"testid":"recommended-list"},"testid":"recommended-item","within":10000},{"actor":"customer","do":"click","in":{"contains":"Headphones","testid":"item-card"},"testid":"add-to-cart"},{"actor":"customer","contains":"Headphones","do":"waitUntilAbsent","in":{"testid":"recommended-list"},"testid":"recommended-item","within":10000}]}],"id":5,"setup":[{"actor":"customer","do":"signUp","name":"recommendations"}]},"packId":"ecommerce.l2.recommendations","role":"feature","source":"scenarios/02-operational-recommendations.json","stablePackId":"ecommerce.inventory-operations"}],"id":"selected-source-040","scenario":{"level":2,"writeUrlPattern":null},"source":"scenarios/02-operational-recommendations.json"},{"checkGroups":[{"checkGroupId":"cancellation-and-return","feature":{"actors":["customer","admin"],"criteria":[{"id":"3a","steps":[{"actor":"admin","as":"revenue-before","do":"recordNumber","testid":"admin-revenue"},{"actor":"customer","as":"stock-before","do":"recordNumber","in":{"contains":"Coffee Grinder","testid":"item-card"},"testid":"item-stock"},{"actor":"customer","do":"click","in":{"contains":"Coffee Grinder","testid":"item-card"},"testid":"buy-now"},{"actor":"customer","do":"expectNumber","in":{"contains":"Coffee Grinder","testid":"item-card"},"plus":-1,"relativeTo":"stock-before","testid":"item-stock","within":10000},{"actor":"admin","do":"reload","settleMs":2000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"admin-link"},{"actor":"admin","do":"expectNumber","plus":64,"relativeTo":"revenue-before","testid":"admin-revenue","within":10000},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"customer","do":"click","settleMs":2000,"testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"customer","do":"expect","ignoreCase":true,"in":{"contains":"Coffee Grinder","testid":"order-item"},"testid":"order-status","value":"pending"},{"actor":"customer","do":"click","in":{"contains":"Coffee Grinder","testid":"order-item"},"testid":"cancel-order"},{"actor":"admin","do":"reload","settleMs":2000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"admin-link"},{"actor":"admin","do":"expectNumber","plus":0,"relativeTo":"revenue-before","testid":"admin-revenue","within":10000},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"catalog-link"},{"actor":"customer","do":"expectNumber","in":{"contains":"Coffee Grinder","testid":"item-card"},"plus":0,"relativeTo":"stock-before","testid":"item-stock","within":10000}]}],"id":3,"setup":[{"actor":"customer","do":"signUp","name":"cancel-core"},{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"click","testid":"admin-link"}]},"packId":"ecommerce.l2.order-cancellation-features","role":"feature","source":"scenarios/02-order-cancellation-core.json","stablePackId":"ecommerce.returns-pricing"}],"id":"selected-source-041","scenario":{"level":2,"writeUrlPattern":null},"source":"scenarios/02-order-cancellation-core.json"},{"checkGroups":[{"checkGroupId":"cancellation-and-return","feature":{"actors":["customer"],"criteria":[{"id":"3b","steps":[{"actor":"customer","do":"click","in":{"contains":"Coffee Grinder","testid":"item-card"},"settleMs":2000,"testid":"buy-now"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"customer","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"customer","do":"click","in":{"contains":"Coffee Grinder","testid":"order-item"},"testid":"cancel-order"},{"actor":"customer","do":"expect","ignoreCase":true,"in":{"contains":"Coffee Grinder","testid":"order-item"},"testid":"order-status","value":"cancelled","within":10000}]}],"id":3,"setup":[{"actor":"customer","do":"signUp","name":"cancel-focused"}]},"packId":"ecommerce.l2.order-cancellation-features","role":"feature","source":"scenarios/02-order-cancellation-history.json","stablePackId":"ecommerce.returns-pricing"}],"id":"selected-source-042","scenario":{"level":2,"writeUrlPattern":null},"source":"scenarios/02-order-cancellation-history.json"},{"checkGroups":[{"checkGroupId":"price-history","feature":{"actors":["admin","customer","visitor"],"criteria":[{"id":"4a","steps":[{"actor":"customer","do":"fill","enter":true,"settleMs":1500,"testid":"search-input","text":"Air Purifier"},{"actor":"customer","as":"air-purifier-paid","do":"recordNumber","in":{"contains":"Air Purifier","testid":"item-card"},"testid":"item-price"},{"actor":"customer","do":"click","in":{"contains":"Air Purifier","testid":"item-card"},"settleMs":2000,"testid":"buy-now"},{"actor":"visitor","do":"fill","enter":true,"settleMs":1500,"testid":"search-input","text":"Air Purifier"},{"actor":"admin","do":"fill","in":{"contains":"Air Purifier","testid":"admin-item-row"},"testid":"price-input","text":"1.00"},{"actor":"admin","do":"click","in":{"contains":"Air Purifier","testid":"admin-item-row"},"testid":"price-submit"},{"actor":"visitor","do":"expectNumber","equals":1,"in":{"contains":"Air Purifier","testid":"item-card"},"testid":"item-price","within":10000},{"actor":"customer","do":"reload","settleMs":2000},{"actor":"customer","do":"ensureSignedIn","name":"history-persisted","readyTestid":"current-user"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"customer","do":"click","testid":"orders-toggle"},{"actor":"customer","do":"expectNumber","in":{"contains":"Air Purifier","testid":"order-item"},"plus":0,"relativeTo":"air-purifier-paid","testid":"order-total"}]}],"id":4,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"customer","do":"signUp","name":"history-persisted"},{"actor":"admin","do":"click","testid":"admin-link"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.progression.price-history-specifications","requiresFeatures":["ecommerce.feature.purchasing","ecommerce.l2.price-history-features"],"role":"guarantee","source":"scenarios/02-paid-price-history.json","stablePackId":"ecommerce.returns-pricing"}],"id":"selected-source-043","scenario":{"level":2,"writeUrlPattern":null},"source":"scenarios/02-paid-price-history.json"},{"checkGroups":[{"checkGroupId":"fulfilment-queue","feature":{"actors":["customer","staff"],"criteria":[{"id":"1b","steps":[{"do":"dbSetStock","item":"Desk Lamp","quantity":0,"settleMs":2000,"warehouse":"West"},{"actor":"customer","do":"click","in":{"contains":"Desk Lamp","testid":"item-card"},"settleMs":1500,"testid":"buy-now"},{"actor":"staff","do":"reload","settleMs":2000},{"actor":"staff","do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026","readyTestid":"current-user"},{"actor":"staff","do":"click","ifAvailable":true,"testid":"staff-link"},{"actor":"staff","contains":"Desk Lamp","do":"expect","testid":"queue-item","within":10000},{"actor":"staff","contains":"East","do":"expect","in":{"contains":"Desk Lamp","testid":"queue-item"},"testid":"queue-warehouse"}]}],"id":1,"setup":[{"actor":"customer","do":"signUp","name":"fq-warehouse"},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"staff","do":"click","testid":"staff-link"}]},"packId":"ecommerce.progression.fulfilment-queue","role":"feature","source":"scenarios/02-queue-warehouse.json","stablePackId":"ecommerce.operations-access"}],"id":"selected-source-044","scenario":{"level":2,"writeUrlPattern":null},"source":"scenarios/02-queue-warehouse.json"},{"checkGroups":[{"checkGroupId":"stock-conservation","feature":{"actors":["customer"],"criteria":[{"id":"202b","steps":[{"as":"east-before-cancel-202b","do":"dbRecordStock","item":"Induction Cooktop","warehouse":"East"},{"as":"west-before-cancel-202b","do":"dbRecordStock","item":"Induction Cooktop","warehouse":"West"},{"as":"stored-before-cancel-202b","do":"dbRecordStock","item":"Induction Cooktop"},{"actor":"customer","as":"cancel-stock-before","do":"recordNumber","in":{"contains":"Induction Cooktop","testid":"item-card"},"testid":"item-stock"},{"actor":"customer","do":"click","in":{"contains":"Induction Cooktop","testid":"item-card"},"settleMs":2000,"testid":"buy-now"},{"actor":"customer","do":"expectNumber","in":{"contains":"Induction Cooktop","testid":"item-card"},"plus":-1,"relativeTo":"cancel-stock-before","testid":"item-stock"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"customer","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"customer","contains":"Induction Cooktop","count":1,"do":"expect","testid":"order-item","within":10000},{"do":"dbExpectStock","item":"Induction Cooktop","plus":-1,"relativeTo":"stored-before-cancel-202b"},{"actor":"customer","do":"click","in":{"contains":"Induction Cooktop","testid":"order-item"},"settleMs":2000,"testid":"cancel-order"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"catalog-link"},{"actor":"customer","do":"expectNumber","in":{"contains":"Induction Cooktop","testid":"item-card"},"plus":0,"relativeTo":"cancel-stock-before","testid":"item-stock"},{"do":"dbExpectStock","item":"Induction Cooktop","plus":0,"relativeTo":"stored-before-cancel-202b"},{"do":"dbExpectStock","item":"Induction Cooktop","plus":0,"relativeTo":"east-before-cancel-202b","warehouse":"East"},{"do":"dbExpectStock","item":"Induction Cooktop","plus":0,"relativeTo":"west-before-cancel-202b","warehouse":"West"}]}],"id":202,"setup":[{"actor":"customer","do":"signUp","name":"fresh-stock"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.progression.inventory-conservation-specifications","requiresFeatures":["ecommerce.l2.order-cancellation-features"],"role":"guarantee","source":"scenarios/02-self-contained.json","stablePackId":"ecommerce.inventory-operations"},{"checkGroupId":"stock-conservation","feature":{"actors":["customer"],"criteria":[{"id":"202c","steps":[{"as":"east-before-cancel-202c","do":"dbRecordStock","item":"Headphones","warehouse":"East"},{"as":"west-before-cancel-202c","do":"dbRecordStock","item":"Headphones","warehouse":"West"},{"as":"stored-before-cancel-202c","do":"dbRecordStock","item":"Headphones"},{"actor":"customer","as":"fresh-stock-before","do":"recordNumber","in":{"contains":"Headphones","testid":"item-card"},"testid":"item-stock"},{"actor":"customer","do":"click","in":{"contains":"Headphones","testid":"item-card"},"settleMs":2000,"testid":"buy-now"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"customer","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"customer","contains":"Headphones","count":1,"do":"expect","testid":"order-item","within":10000},{"do":"dbExpectStock","item":"Headphones","plus":-1,"relativeTo":"stored-before-cancel-202c"},{"actor":"customer","do":"click","in":{"contains":"Headphones","testid":"order-item"},"settleMs":2000,"testid":"cancel-order"},{"actor":"customer","do":"freshClient"},{"actor":"customer-fresh","do":"expectNumber","in":{"contains":"Headphones","testid":"item-card"},"plus":0,"relativeTo":"fresh-stock-before","testid":"item-stock"},{"do":"dbExpectStock","item":"Headphones","plus":0,"relativeTo":"stored-before-cancel-202c"},{"do":"dbExpectStock","item":"Headphones","plus":0,"relativeTo":"east-before-cancel-202c","warehouse":"East"},{"do":"dbExpectStock","item":"Headphones","plus":0,"relativeTo":"west-before-cancel-202c","warehouse":"West"}]}],"id":202,"setup":[{"actor":"customer","do":"signUp","name":"fresh-stock"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.progression.inventory-conservation-specifications","requiresFeatures":["ecommerce.l2.order-cancellation-features"],"role":"guarantee","source":"scenarios/02-self-contained.json","stablePackId":"ecommerce.inventory-operations"}],"id":"selected-source-045","scenario":{"level":2,"writeUrlPattern":null},"source":"scenarios/02-self-contained.json"},{"checkGroups":[{"checkGroupId":"operator-authorization","feature":{"actors":["customer","staff"],"criteria":[{"id":"201c","steps":[{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"customer","do":"click","ifAvailable":true,"testid":"catalog-link","within":1000},{"actor":"customer","do":"click","in":{"contains":"Coffee Grinder","testid":"item-card"},"settleMs":2000,"testid":"buy-now"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"customer","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"customer","contains":"Coffee Grinder","count":1,"do":"expect","testid":"order-item","within":10000},{"action":"ship","actor":"staff","do":"callAction","from":"customer","input":{"attribute":"data-ship-input","contains":"Coffee Grinder","testid":"order-item"},"namedAction":{"args":[0],"id":"ship","params":[{"in":"body","name":"orderId","wireType":"u64"}],"path":"/api/fulfilment/ship","reducer":"ship_order"},"settleMs":2000},{"actor":"staff","do":"expectActionOutcome","outcome":"accepted"},{"actor":"customer","do":"reload","settleMs":2000},{"actor":"customer","do":"ensureSignedIn","name":"direct-notstaff","readyTestid":"current-user"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"customer","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"customer","do":"expect","ignoreCase":true,"in":{"contains":"Coffee Grinder","testid":"order-item"},"testid":"order-status","value":"shipped","within":10000},{"action":"ship","actor":"customer","do":"callAction","input":{"attribute":"data-ship-input","contains":"Laptop Stand","testid":"order-item"},"namedAction":{"args":[0],"id":"ship","params":[{"in":"body","name":"orderId","wireType":"u64"}],"path":"/api/fulfilment/ship","reducer":"ship_order"},"settleMs":2000},{"actor":"customer","do":"expectActionOutcome","outcome":"refused","routeProvenBy":"staff"},{"actor":"customer","do":"reload","settleMs":2000},{"actor":"customer","do":"ensureSignedIn","name":"direct-notstaff","readyTestid":"current-user"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"customer","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"customer","do":"expect","ignoreCase":true,"in":{"contains":"Laptop Stand","testid":"order-item"},"testid":"order-status","value":"pending"}]}],"id":201,"setup":[{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"customer","do":"signUp","name":"direct-notstaff"},{"actor":"customer","do":"click","in":{"contains":"Laptop Stand","testid":"item-card"},"settleMs":2000,"testid":"buy-now"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"customer","do":"click","testid":"orders-toggle","unlessVisible":"order-item"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.progression.operations-access-specifications","requiresFeatures":["ecommerce.feature.purchasing","ecommerce.progression.fulfilment-queue"],"role":"guarantee","source":"scenarios/02-server-actions.json","stablePackId":"ecommerce.operations-access"},{"checkGroupId":"stock-conservation","feature":{"actors":["admin","customer"],"criteria":[{"id":"202d","steps":[{"do":"dbExpectStock","equals":60,"item":"Headphones","warehouse":"East"},{"do":"dbExpectStock","equals":40,"item":"Headphones","warehouse":"West"},{"as":"direct-race-stock-before","do":"dbRecordStock","item":"Headphones"},{"actor":"admin","do":"reload","settleMs":2000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"admin-link","within":1000},{"actor":"customer","do":"reload","settleMs":2000},{"actor":"customer","do":"ensureSignedIn","name":"direct-conserve","readyTestid":"current-user"},{"actor":"admin","do":"fill","in":{"contains":"Headphones","testid":"admin-item-row"},"testid":"transfer-from","text":"East"},{"actor":"admin","do":"fill","in":{"contains":"Headphones","testid":"admin-item-row"},"testid":"transfer-to","text":"West"},{"actor":"admin","do":"fill","in":{"contains":"Headphones","testid":"admin-item-row"},"testid":"transfer-qty","text":"25"},{"branches":[[{"action":"transfer","actor":"admin","do":"callAction","input":{"attribute":"data-transfer-input","contains":"Headphones","testid":"admin-item-row"},"namedAction":{"args":[0,0,0,25],"id":"transfer","params":[{"in":"body","name":"itemId","wireType":"u64"},{"in":"body","name":"fromWarehouseId","wireType":"u64"},{"in":"body","name":"toWarehouseId","wireType":"u64"},{"in":"body","name":"quantity"}],"path":"/api/admin/transfer","reducer":"admin_transfer_stock"}}],[{"action":"buy","actor":"customer","do":"callAction","input":{"attribute":"data-buy-input","contains":"Headphones","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"}}]],"do":"race","settleMs":5000},{"actor":"admin","do":"expectActionOutcome","outcome":"accepted"},{"actor":"customer","do":"expectActionOutcome","outcome":"accepted"},{"actor":"admin","do":"reload","settleMs":2000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"admin-link","within":1000},{"actor":"admin","do":"expectNumber","in":{"contains":"Headphones","testid":"admin-item-row"},"plus":-1,"relativeTo":"direct-race-stock-before","testid":"admin-stock","within":12000},{"actor":"customer","do":"reload","settleMs":2000},{"actor":"customer","do":"ensureSignedIn","name":"direct-conserve","readyTestid":"current-user"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"customer","do":"click","ifAvailable":true,"testid":"catalog-link","within":1000},{"actor":"customer","do":"expectNumber","in":{"contains":"Headphones","testid":"item-card"},"plus":-1,"relativeTo":"direct-race-stock-before","testid":"item-stock","within":12000},{"atLeast":34,"atMost":35,"do":"dbExpectStock","item":"Headphones","warehouse":"East"},{"atLeast":64,"atMost":65,"do":"dbExpectStock","item":"Headphones","warehouse":"West"},{"do":"dbExpectStock","item":"Headphones","plus":-1,"relativeTo":"direct-race-stock-before"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"customer","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"customer","contains":"Headphones","count":1,"do":"expect","testid":"order-item","within":10000}]}],"id":202,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"customer","do":"signUp","name":"direct-conserve"},{"actor":"admin","do":"click","testid":"admin-link"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.progression.inventory-conservation-specifications","requiresFeatures":["ecommerce.feature.purchasing","ecommerce.l2.stock-transfers-features"],"role":"guarantee","source":"scenarios/02-server-actions.json","stablePackId":"ecommerce.inventory-operations"},{"checkGroupId":"order-owner","feature":{"actors":["owner","other"],"criteria":[{"id":"204a","steps":[{"action":"cancel","actor":"owner","do":"callAction","input":{"attribute":"data-cancel-input","contains":"Desk Lamp","testid":"order-item"},"namedAction":{"args":[0],"id":"cancel","params":[{"in":"path","name":"orderId","placeholder":":id","wireType":"u64"}],"path":"/api/orders/:id/cancel","reducer":"cancel_order"},"settleMs":2000},{"actor":"owner","do":"expectActionOutcome","outcome":"accepted"},{"action":"cancel","actor":"other","do":"callAction","from":"owner","input":{"attribute":"data-cancel-input","contains":"Keyboard","testid":"order-item"},"namedAction":{"args":[0],"id":"cancel","params":[{"in":"path","name":"orderId","placeholder":":id","wireType":"u64"}],"path":"/api/orders/:id/cancel","reducer":"cancel_order"},"settleMs":2000},{"actor":"other","do":"expectActionOutcome","outcome":"refused","routeProvenBy":"owner"},{"actor":"owner","do":"reload","settleMs":1000},{"actor":"owner","do":"ensureSignedIn","name":"direct-owner","readyTestid":"current-user"},{"actor":"owner","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"owner","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"owner","do":"expect","ignoreCase":true,"in":{"contains":"Keyboard","testid":"order-item"},"testid":"order-status","value":"pending"}]}],"id":204,"setup":[{"actor":"owner","do":"signUp","name":"direct-owner"},{"actor":"other","do":"signUp","name":"direct-other"},{"action":"buy","actor":"owner","do":"callAction","input":{"attribute":"data-buy-input","contains":"Desk Lamp","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"}},{"actor":"owner","do":"expectActionOutcome","outcome":"accepted"},{"action":"buy","actor":"owner","do":"callAction","input":{"attribute":"data-buy-input","contains":"Keyboard","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"}},{"actor":"owner","do":"expectActionOutcome","outcome":"accepted"},{"actor":"owner","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"owner","do":"click","testid":"orders-toggle","unlessVisible":"order-item"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.progression.operations-access-specifications","requiresFeatures":["ecommerce.feature.purchasing","ecommerce.l2.order-cancellation-features"],"role":"guarantee","source":"scenarios/02-server-actions.json","stablePackId":"ecommerce.operations-access"}],"id":"selected-source-046","scenario":{"level":2,"writeUrlPattern":null},"source":"scenarios/02-server-actions.json"},{"checkGroups":[{"checkGroupId":"warehouse-transfer","feature":{"actors":["admin","visitor"],"criteria":[{"id":"2a","steps":[{"as":"product-East","do":"dbRecordStock","item":"Headphones","warehouse":"East"},{"as":"product-West","do":"dbRecordStock","item":"Headphones","warehouse":"West"},{"actor":"visitor","as":"transfer-item-before","do":"recordNumber","in":{"contains":"Headphones","testid":"item-card"},"testid":"item-stock"},{"actor":"admin","contains":"East","count":1,"do":"expect","testid":"admin-warehouse-item"},{"actor":"admin","as":"transfer-east-before","do":"recordNumber","in":{"contains":"East","testid":"admin-warehouse-item"},"testid":"warehouse-total"},{"actor":"admin","contains":"West","count":1,"do":"expect","testid":"admin-warehouse-item"},{"actor":"admin","as":"transfer-west-before","do":"recordNumber","in":{"contains":"West","testid":"admin-warehouse-item"},"testid":"warehouse-total"},{"actor":"admin","do":"fill","in":{"contains":"Headphones","testid":"admin-item-row"},"testid":"transfer-from","text":"East"},{"actor":"admin","do":"fill","in":{"contains":"Headphones","testid":"admin-item-row"},"testid":"transfer-to","text":"West"},{"actor":"admin","do":"fill","in":{"contains":"Headphones","testid":"admin-item-row"},"testid":"transfer-qty","text":"10"},{"actor":"admin","do":"click","in":{"contains":"Headphones","testid":"admin-item-row"},"testid":"transfer-submit"},{"actor":"admin","contains":"East","count":1,"do":"expect","testid":"admin-warehouse-item"},{"do":"dbExpectStock","item":"Headphones","plus":-10,"relativeTo":"product-East","warehouse":"East","within":10000},{"do":"dbExpectStock","item":"Headphones","plus":10,"relativeTo":"product-West","warehouse":"West","within":10000},{"actor":"admin","do":"expectNumber","in":{"contains":"East","testid":"admin-warehouse-item"},"plus":-10,"relativeTo":"transfer-east-before","testid":"warehouse-total","within":10000},{"actor":"admin","contains":"West","count":1,"do":"expect","testid":"admin-warehouse-item"},{"actor":"admin","do":"expectNumber","in":{"contains":"West","testid":"admin-warehouse-item"},"plus":10,"relativeTo":"transfer-west-before","testid":"warehouse-total","within":10000},{"actor":"visitor","do":"expectNumber","in":{"contains":"Headphones","testid":"item-card"},"plus":0,"relativeTo":"transfer-item-before","testid":"item-stock","within":10000}]}],"id":2,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"click","testid":"admin-link"}]},"packId":"ecommerce.l2.stock-transfers-features","role":"feature","source":"scenarios/02-strengthened.json","stablePackId":"ecommerce.inventory-operations"},{"checkGroupId":"operator-authorization","feature":{"actors":["admin","customer"],"criteria":[{"id":"201a","steps":[{"as":"authorized-transfer-east","do":"dbRecordStock","item":"Headphones","warehouse":"East"},{"as":"authorized-transfer-west","do":"dbRecordStock","item":"Headphones","warehouse":"West"},{"actor":"admin","do":"fill","in":{"contains":"Headphones","testid":"admin-item-row"},"testid":"transfer-from","text":"East"},{"actor":"admin","do":"fill","in":{"contains":"Headphones","testid":"admin-item-row"},"testid":"transfer-to","text":"West"},{"actor":"admin","do":"fill","in":{"contains":"Headphones","testid":"admin-item-row"},"testid":"transfer-qty","text":"25"},{"action":"transfer","actor":"admin","do":"callAction","input":{"attribute":"data-transfer-input","contains":"Headphones","testid":"admin-item-row"},"namedAction":{"args":[0,0,0,25],"id":"transfer","params":[{"in":"body","name":"itemId","wireType":"u64"},{"in":"body","name":"fromWarehouseId","wireType":"u64"},{"in":"body","name":"toWarehouseId","wireType":"u64"},{"in":"body","name":"quantity"}],"path":"/api/admin/transfer","reducer":"admin_transfer_stock"},"settleMs":2000},{"actor":"admin","do":"expectActionOutcome","outcome":"accepted"},{"do":"dbExpectStock","item":"Headphones","plus":-25,"relativeTo":"authorized-transfer-east","warehouse":"East"},{"do":"dbExpectStock","item":"Headphones","plus":25,"relativeTo":"authorized-transfer-west","warehouse":"West"},{"actor":"admin","do":"reload","settleMs":2000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"admin-link","within":1000},{"actor":"customer","do":"reload","settleMs":2000},{"actor":"customer","do":"ensureSignedIn","name":"not-operator","readyTestid":"current-user"},{"actor":"customer","as":"unauthorized-item-before","do":"recordNumber","in":{"contains":"Headphones","testid":"item-card"},"testid":"item-stock"},{"actor":"admin","contains":"East","count":1,"do":"expect","testid":"admin-warehouse-item"},{"actor":"admin","as":"unauthorized-east-before","do":"recordNumber","in":{"contains":"East","testid":"admin-warehouse-item"},"testid":"warehouse-total"},{"actor":"admin","contains":"West","count":1,"do":"expect","testid":"admin-warehouse-item"},{"actor":"admin","as":"unauthorized-west-before","do":"recordNumber","in":{"contains":"West","testid":"admin-warehouse-item"},"testid":"warehouse-total"},{"actor":"admin","do":"fill","in":{"contains":"Headphones","testid":"admin-item-row"},"testid":"transfer-from","text":"East"},{"actor":"admin","do":"fill","in":{"contains":"Headphones","testid":"admin-item-row"},"testid":"transfer-to","text":"West"},{"as":"refused-East","do":"dbRecordStock","item":"Headphones","warehouse":"East"},{"as":"refused-West","do":"dbRecordStock","item":"Headphones","warehouse":"West"},{"action":"transfer","actor":"customer","do":"callAction","from":"admin","input":{"attribute":"data-transfer-input","contains":"Headphones","testid":"admin-item-row"},"namedAction":{"args":[0,0,0,25],"id":"transfer","params":[{"in":"body","name":"itemId","wireType":"u64"},{"in":"body","name":"fromWarehouseId","wireType":"u64"},{"in":"body","name":"toWarehouseId","wireType":"u64"},{"in":"body","name":"quantity"}],"path":"/api/admin/transfer","reducer":"admin_transfer_stock"},"settleMs":2000},{"actor":"customer","do":"expectActionOutcome","outcome":"refused","routeProvenBy":"admin"},{"actor":"admin","do":"reload","settleMs":2000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"admin-link","within":1000},{"actor":"customer","do":"reload","settleMs":2000},{"actor":"customer","do":"ensureSignedIn","name":"not-operator","readyTestid":"current-user"},{"actor":"admin","contains":"East","count":1,"do":"expect","testid":"admin-warehouse-item"},{"do":"dbExpectStock","item":"Headphones","plus":0,"relativeTo":"refused-East","warehouse":"East"},{"do":"dbExpectStock","item":"Headphones","plus":0,"relativeTo":"refused-West","warehouse":"West"},{"actor":"admin","do":"expectNumber","in":{"contains":"East","testid":"admin-warehouse-item"},"plus":0,"relativeTo":"unauthorized-east-before","testid":"warehouse-total"},{"actor":"admin","contains":"West","count":1,"do":"expect","testid":"admin-warehouse-item"},{"actor":"admin","do":"expectNumber","in":{"contains":"West","testid":"admin-warehouse-item"},"plus":0,"relativeTo":"unauthorized-west-before","testid":"warehouse-total"},{"actor":"customer","do":"expectNumber","in":{"contains":"Headphones","testid":"item-card"},"plus":0,"relativeTo":"unauthorized-item-before","testid":"item-stock"}]}],"id":201,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"customer","do":"signUp","name":"not-operator"},{"actor":"admin","do":"click","testid":"admin-link"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.progression.operations-access-specifications","requiresFeatures":["ecommerce.l2.stock-transfers-features"],"role":"guarantee","source":"scenarios/02-strengthened.json","stablePackId":"ecommerce.operations-access"},{"checkGroupId":"operator-authorization","feature":{"actors":["admin","customer"],"criteria":[{"id":"201b","steps":[{"actor":"admin","do":"fill","in":{"contains":"Gaming Mouse","testid":"admin-item-row"},"testid":"price-input","text":"77.00"},{"action":"price","actor":"admin","do":"callAction","input":{"attribute":"data-price-input","contains":"Gaming Mouse","testid":"admin-item-row"},"namedAction":{"args":[0,1],"id":"price","params":[{"in":"body","name":"itemId","wireType":"u64"},{"in":"body","name":"price"}],"path":"/api/admin/price","reducer":"admin_change_price"},"settleMs":2000},{"actor":"admin","do":"expectActionOutcome","outcome":"accepted"},{"actor":"customer","do":"reload","settleMs":2000},{"actor":"customer","do":"ensureSignedIn","name":"not-operator","readyTestid":"current-user"},{"actor":"customer","do":"expectNumber","equals":77,"in":{"contains":"Gaming Mouse","testid":"item-card"},"testid":"item-price","within":10000},{"actor":"admin","do":"fill","in":{"contains":"Gaming Mouse","testid":"admin-item-row"},"testid":"price-input","text":"1.00"},{"action":"price","actor":"customer","do":"callAction","from":"admin","input":{"attribute":"data-price-input","contains":"Gaming Mouse","testid":"admin-item-row"},"namedAction":{"args":[0,1],"id":"price","params":[{"in":"body","name":"itemId","wireType":"u64"},{"in":"body","name":"price"}],"path":"/api/admin/price","reducer":"admin_change_price"},"settleMs":2000},{"actor":"customer","do":"expectActionOutcome","outcome":"refused","routeProvenBy":"admin"},{"actor":"admin","do":"reload","settleMs":2000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"admin-link","within":1000},{"actor":"customer","do":"reload","settleMs":2000},{"actor":"customer","do":"ensureSignedIn","name":"not-operator","readyTestid":"current-user"},{"actor":"customer","do":"expectNumber","equals":77,"in":{"contains":"Gaming Mouse","testid":"item-card"},"testid":"item-price","within":10000}]}],"id":201,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"customer","do":"signUp","name":"not-operator"},{"actor":"admin","do":"click","testid":"admin-link"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.progression.operations-access-specifications","requiresFeatures":["ecommerce.l2.price-history-features"],"role":"guarantee","source":"scenarios/02-strengthened.json","stablePackId":"ecommerce.operations-access"},{"checkGroupId":"stock-conservation","feature":{"actors":["admin","customer"],"criteria":[{"id":"202a","steps":[{"as":"product-East","do":"dbRecordStock","item":"Espresso Machine","warehouse":"East"},{"as":"product-West","do":"dbRecordStock","item":"Espresso Machine","warehouse":"West"},{"actor":"customer","as":"conservation-item-before","do":"recordNumber","in":{"contains":"Espresso Machine","testid":"item-card"},"testid":"item-stock"},{"actor":"admin","contains":"East","count":1,"do":"expect","testid":"admin-warehouse-item"},{"actor":"admin","as":"conservation-east-before","do":"recordNumber","in":{"contains":"East","testid":"admin-warehouse-item"},"testid":"warehouse-total"},{"actor":"admin","contains":"West","count":1,"do":"expect","testid":"admin-warehouse-item"},{"actor":"admin","as":"conservation-west-before","do":"recordNumber","in":{"contains":"West","testid":"admin-warehouse-item"},"testid":"warehouse-total"},{"actor":"admin","do":"fill","in":{"contains":"Espresso Machine","testid":"admin-item-row"},"testid":"transfer-from","text":"East"},{"actor":"admin","do":"fill","in":{"contains":"Espresso Machine","testid":"admin-item-row"},"testid":"transfer-to","text":"West"},{"actor":"admin","do":"fill","in":{"contains":"Espresso Machine","testid":"admin-item-row"},"testid":"transfer-qty","text":"17"},{"actor":"admin","do":"click","in":{"contains":"Espresso Machine","testid":"admin-item-row"},"testid":"transfer-submit"},{"actor":"admin","contains":"East","count":1,"do":"expect","testid":"admin-warehouse-item"},{"do":"dbExpectStock","item":"Espresso Machine","plus":-17,"relativeTo":"product-East","warehouse":"East","within":10000},{"do":"dbExpectStock","item":"Espresso Machine","plus":17,"relativeTo":"product-West","warehouse":"West","within":10000},{"actor":"admin","do":"reload","settleMs":1000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","testid":"admin-link","unlessVisible":"admin-revenue"},{"actor":"admin","do":"expectNumber","in":{"contains":"East","testid":"admin-warehouse-item"},"plus":-17,"relativeTo":"conservation-east-before","testid":"warehouse-total","within":10000},{"actor":"admin","contains":"West","count":1,"do":"expect","testid":"admin-warehouse-item"},{"actor":"admin","do":"expectNumber","in":{"contains":"West","testid":"admin-warehouse-item"},"plus":17,"relativeTo":"conservation-west-before","testid":"warehouse-total","within":10000},{"actor":"customer","do":"expectNumber","in":{"contains":"Espresso Machine","testid":"item-card"},"plus":0,"relativeTo":"conservation-item-before","testid":"item-stock","within":10000}]}],"id":202,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"customer","do":"signUp","name":"directional-stock"},{"actor":"admin","do":"click","testid":"admin-link"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.progression.inventory-conservation-specifications","requiresFeatures":["ecommerce.l2.stock-transfers-features"],"role":"guarantee","source":"scenarios/02-strengthened.json","stablePackId":"ecommerce.inventory-operations"}],"id":"selected-source-047","scenario":{"level":2,"writeUrlPattern":null},"source":"scenarios/02-strengthened.json"},{"checkGroups":[{"checkGroupId":"stock-transfer-overdraw","feature":{"actors":["admin","visitor"],"criteria":[{"id":"2c","steps":[{"as":"product-East","do":"dbRecordStock","item":"Headphones","warehouse":"East"},{"as":"product-West","do":"dbRecordStock","item":"Headphones","warehouse":"West"},{"actor":"visitor","as":"overdraw-item-before","do":"recordNumber","in":{"contains":"Headphones","testid":"item-card"},"testid":"item-stock"},{"actor":"admin","as":"overdraw-east-before","do":"recordNumber","in":{"contains":"East","testid":"admin-warehouse-item"},"testid":"warehouse-total"},{"actor":"admin","as":"overdraw-west-before","do":"recordNumber","in":{"contains":"West","testid":"admin-warehouse-item"},"testid":"warehouse-total"},{"actor":"admin","do":"fill","in":{"contains":"Headphones","testid":"admin-item-row"},"testid":"transfer-from","text":"East"},{"actor":"admin","do":"fill","in":{"contains":"Headphones","testid":"admin-item-row"},"testid":"transfer-to","text":"West"},{"actor":"admin","do":"fill","in":{"contains":"Headphones","testid":"admin-item-row"},"testid":"transfer-qty","text":"99999"},{"actor":"admin","do":"click","in":{"contains":"Headphones","testid":"admin-item-row"},"testid":"transfer-submit"},{"actor":"admin","do":"expect","testid":"order-error","within":6000},{"do":"dbExpectStock","item":"Headphones","plus":0,"relativeTo":"product-East","warehouse":"East"},{"do":"dbExpectStock","item":"Headphones","plus":0,"relativeTo":"product-West","warehouse":"West"},{"actor":"admin","do":"expectNumber","in":{"contains":"East","testid":"admin-warehouse-item"},"plus":0,"relativeTo":"overdraw-east-before","testid":"warehouse-total"},{"actor":"admin","do":"expectNumber","in":{"contains":"West","testid":"admin-warehouse-item"},"plus":0,"relativeTo":"overdraw-west-before","testid":"warehouse-total"},{"actor":"visitor","do":"expectNumber","in":{"contains":"Headphones","testid":"item-card"},"plus":0,"relativeTo":"overdraw-item-before","testid":"item-stock"}]}],"id":2,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"click","testid":"admin-link"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.transactional-integrity","requiresFeatures":["ecommerce.l2.stock-transfers-features"],"role":"guarantee","source":"scenarios/02-transfer-overdraw.json"}],"id":"selected-source-048","scenario":{"level":2,"writeUrlPattern":null},"source":"scenarios/02-transfer-overdraw.json"},{"checkGroups":[{"checkGroupId":"stock-transfers","feature":{"actors":["admin"],"criteria":[{"id":"2b","steps":[{"as":"product-East","do":"dbRecordStock","item":"Headphones","warehouse":"East"},{"as":"product-West","do":"dbRecordStock","item":"Headphones","warehouse":"West"},{"actor":"admin","contains":"East","count":1,"do":"expect","testid":"admin-warehouse-item"},{"actor":"admin","as":"warehouse-east-before","do":"recordNumber","in":{"contains":"East","testid":"admin-warehouse-item"},"testid":"warehouse-total"},{"actor":"admin","contains":"West","count":1,"do":"expect","testid":"admin-warehouse-item"},{"actor":"admin","as":"warehouse-west-before","do":"recordNumber","in":{"contains":"West","testid":"admin-warehouse-item"},"testid":"warehouse-total"},{"actor":"admin","do":"fill","in":{"contains":"Headphones","testid":"admin-item-row"},"testid":"transfer-from","text":"East"},{"actor":"admin","do":"fill","in":{"contains":"Headphones","testid":"admin-item-row"},"testid":"transfer-to","text":"West"},{"actor":"admin","do":"fill","in":{"contains":"Headphones","testid":"admin-item-row"},"testid":"transfer-qty","text":"10"},{"actor":"admin","do":"click","in":{"contains":"Headphones","testid":"admin-item-row"},"testid":"transfer-submit"},{"actor":"admin","contains":"East","count":1,"do":"expect","testid":"admin-warehouse-item"},{"actor":"admin","do":"expectNumber","in":{"contains":"East","testid":"admin-warehouse-item"},"plus":-10,"relativeTo":"warehouse-east-before","testid":"warehouse-total","within":10000},{"actor":"admin","contains":"West","count":1,"do":"expect","testid":"admin-warehouse-item"},{"actor":"admin","do":"expectNumber","in":{"contains":"West","testid":"admin-warehouse-item"},"plus":10,"relativeTo":"warehouse-west-before","testid":"warehouse-total","within":10000},{"do":"dbExpectStock","item":"Headphones","plus":-10,"relativeTo":"product-East","warehouse":"East","within":10000},{"do":"dbExpectStock","item":"Headphones","plus":10,"relativeTo":"product-West","warehouse":"West","within":10000}]}],"id":2,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"click","testid":"admin-link"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.live-state","requiresFeatures":["ecommerce.l2.stock-transfers-features"],"role":"guarantee","source":"scenarios/02-transfer-totals.json"}],"id":"selected-source-049","scenario":{"level":2,"writeUrlPattern":null},"source":"scenarios/02-transfer-totals.json"},{"checkGroups":[{"checkGroupId":"cart-expiration","feature":{"actors":["customer","watcher"],"criteria":[{"id":"304a","steps":[{"actor":"watcher","do":"wait","ms":310000},{"actor":"watcher","do":"reload","settleMs":1000},{"actor":"watcher","do":"expectNumber","in":{"contains":"Air Purifier","testid":"item-card"},"plus":0,"relativeTo":"before","testid":"item-stock","within":30000},{"actor":"customer","do":"openClient","settleMs":3000},{"actor":"customer","do":"expect","testid":"cart-expired-notice","within":10000},{"actor":"customer","do":"expectNumber","equals":0,"testid":"cart-count"}]}],"id":304,"setup":[{"actor":"customer","do":"signUp","name":"cart-expiry"},{"actor":"watcher","as":"before","do":"recordNumber","in":{"contains":"Air Purifier","testid":"item-card"},"testid":"item-stock"},{"actor":"customer","do":"click","in":{"contains":"Air Purifier","testid":"item-card"},"testid":"add-to-cart"},{"actor":"watcher","do":"reload","settleMs":1000},{"actor":"watcher","do":"expectNumber","in":{"contains":"Air Purifier","testid":"item-card"},"plus":-1,"relativeTo":"before","testid":"item-stock","within":10000},{"actor":"customer","do":"closeClient"}]},"packId":"ecommerce.l3.cart-expiration-features","role":"feature","source":"scenarios/03-cart-expiration.json","stablePackId":"ecommerce.l3.cart-expiration"}],"id":"selected-source-050","scenario":{"level":3,"writeUrlPattern":null},"source":"scenarios/03-cart-expiration.json"},{"checkGroups":[{"checkGroupId":"scheduled-work-access","feature":{"actors":["admin","customer"],"criteria":[{"id":"317a","steps":[{"actor":"admin","do":"fill","testid":"schedule-restock-item","text":"Webcam"},{"actor":"admin","do":"fill","testid":"schedule-restock-warehouse","text":"West"},{"actor":"admin","do":"fill","testid":"schedule-restock-qty","text":"3"},{"actor":"admin","do":"fill","testid":"schedule-restock-delay","text":"180"},{"action":"scheduleRestock","actor":"customer","authentication":"actor","do":"callAction","from":"admin","input":{"attribute":"data-action-input","testid":"schedule-restock-submit"},"namedAction":{"args":["","",0,0],"id":"scheduleRestock","method":"POST","params":[{"in":"body","name":"item"},{"in":"body","name":"warehouse"},{"in":"body","name":"quantity"},{"in":"body","name":"delaySeconds"}],"path":"/api/admin/scheduled-restocks","reducer":"schedule_restock"},"settleMs":2000},{"actor":"customer","do":"expectActionOutcome","outcome":"refused"},{"actor":"customer","do":"replayAs","from":"admin","match":"DELETE","namedAction":{"args":[0],"id":"cancelScheduledRestock","method":"DELETE","params":[{"in":"path","name":"restockId","placeholder":"{restockId}","wireType":"u64"}],"path":"/api/admin/scheduled-restocks/{restockId}","reducer":"cancel_scheduled_restock"},"namedTarget":{"attribute":"data-entity-id","testid":"pending-restock-item","valueType":"string"},"settleMs":2000},{"actor":"customer","do":"expectReplayRejected"},{"actor":"admin","count":1,"do":"expect","testid":"pending-restock-item"},{"actor":"admin","do":"click","in":{"testid":"pending-restock-item"},"testid":"pending-restock-cancel"}]}],"id":317,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"click","testid":"admin-link"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"restocks-link"},{"actor":"customer","do":"signUp","name":"restock-outsider"},{"actor":"admin","do":"fill","testid":"schedule-restock-item","text":"Webcam"},{"actor":"admin","do":"fill","testid":"schedule-restock-warehouse","text":"West"},{"actor":"admin","do":"fill","testid":"schedule-restock-qty","text":"3"},{"actor":"admin","do":"fill","testid":"schedule-restock-delay","text":"180"},{"actor":"admin","do":"click","testid":"schedule-restock-submit"},{"actor":"admin","count":1,"do":"expect","testid":"pending-restock-item"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.l3.deferred-access-specifications","requiresFeatures":["ecommerce.l3.scheduled-restocks-features"],"role":"guarantee","source":"scenarios/03-deferred-access.json","stablePackId":"ecommerce.l3.deferred-access"}],"id":"selected-source-051","scenario":{"level":3,"writeUrlPattern":null},"source":"scenarios/03-deferred-access.json"},{"checkGroups":[{"checkGroupId":"restart-survival","feature":{"actors":["admin"],"criteria":[{"id":"311a","steps":[{"do":"dbExpectStock","item":"Air Purifier","plus":5,"relativeTo":"before","within":70000},{"actor":"admin","do":"reload","settleMs":2000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"admin-link"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"restocks-link"},{"actor":"admin","do":"expect","testid":"schedule-restock-submit"},{"absent":true,"actor":"admin","do":"expect","testid":"pending-restock-item"}]}],"id":311,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"click","testid":"admin-link"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"restocks-link"},{"as":"ordinaryBefore","do":"dbRecordStock","item":"Air Purifier"},{"actor":"admin","do":"fill","testid":"schedule-restock-item","text":"Air Purifier"},{"actor":"admin","do":"fill","testid":"schedule-restock-warehouse","text":"East"},{"actor":"admin","do":"fill","testid":"schedule-restock-qty","text":"5"},{"actor":"admin","do":"fill","testid":"schedule-restock-delay","text":"45"},{"actor":"admin","do":"click","testid":"schedule-restock-submit"},{"actor":"admin","count":1,"do":"expect","testid":"pending-restock-item","within":10000},{"do":"dbExpectStock","item":"Air Purifier","plus":5,"relativeTo":"ordinaryBefore","within":70000},{"actor":"admin","do":"reload","settleMs":1000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","testid":"admin-link"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"restocks-link"},{"actor":"admin","do":"expect","testid":"schedule-restock-submit"},{"absent":true,"actor":"admin","do":"expect","testid":"pending-restock-item"},{"as":"before","do":"dbRecordStock","item":"Air Purifier"},{"actor":"admin","do":"fill","testid":"schedule-restock-item","text":"Air Purifier"},{"actor":"admin","do":"fill","testid":"schedule-restock-warehouse","text":"East"},{"actor":"admin","do":"fill","testid":"schedule-restock-qty","text":"5"},{"actor":"admin","do":"fill","testid":"schedule-restock-delay","text":"45"},{"actor":"admin","do":"click","testid":"schedule-restock-submit"},{"actor":"admin","count":1,"do":"expect","testid":"pending-restock-item","within":10000},{"do":"dbExpectStock","item":"Air Purifier","plus":0,"relativeTo":"before"},{"do":"restartBackend","settleMs":15000}]},"observations":["requested","unmentioned"],"packId":"ecommerce.l3.deferred-durability-specifications","requiresFeatures":["ecommerce.l3.scheduled-restocks-features"],"role":"guarantee","source":"scenarios/03-deferred-durability.json","stablePackId":"ecommerce.l3.deferred-durability"},{"checkGroupId":"restart-survival","feature":{"actors":["customer","watcher"],"criteria":[{"id":"314a","steps":[{"atMost":70000,"do":"expectElapsed","since":"pending-314"},{"actor":"watcher","do":"reload","settleMs":1000},{"atMost":70000,"do":"expectElapsed","since":"pending-314"},{"actor":"watcher","do":"expectNumber","in":{"contains":"Desk Lamp","testid":"item-card"},"plus":-1,"relativeTo":"before","testid":"item-stock","within":1000},{"atMost":70000,"do":"expectElapsed","since":"pending-314"},{"actor":"customer","do":"wait","ms":110000,"since":"pending-314-accepted"},{"actor":"watcher","do":"reload","settleMs":2000},{"actor":"watcher","do":"expectNumber","in":{"contains":"Desk Lamp","testid":"item-card"},"plus":0,"relativeTo":"before","testid":"item-stock","within":10000},{"actor":"customer","do":"reload","settleMs":1000},{"actor":"customer","do":"ensureSignedIn","name":"durable-reservation","readyTestid":"current-user"},{"actor":"customer","do":"click","testid":"cart-toggle","unlessVisible":"cart-item"},{"actor":"customer","do":"expect","in":{"contains":"Desk Lamp","testid":"cart-item"},"testid":"cart-item-expired","within":10000}]}],"id":314,"setup":[{"actor":"customer","do":"signUp","name":"durable-reservation"},{"actor":"watcher","as":"before","do":"recordNumber","in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"item-stock"},{"as":"pending-314","do":"recordTime"},{"actor":"customer","do":"click","in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"add-to-cart"},{"actor":"watcher","do":"reload","settleMs":1000},{"actor":"watcher","do":"expectNumber","in":{"contains":"Desk Lamp","testid":"item-card"},"plus":-1,"relativeTo":"before","testid":"item-stock","within":10000},{"as":"pending-314-accepted","do":"recordTime"},{"actor":"customer","do":"wait","ms":30000},{"do":"restartBackend","settleMs":15000},{"actor":"watcher","do":"reload","settleMs":3000}]},"observations":["requested","unmentioned"],"packId":"ecommerce.l3.deferred-durability-specifications","requiresFeatures":["ecommerce.l3.reservations-features"],"role":"guarantee","source":"scenarios/03-deferred-durability.json","stablePackId":"ecommerce.l3.deferred-durability"},{"checkGroupId":"restart-survival","feature":{"actors":["customer","staff"],"criteria":[{"id":"315a","steps":[{"actor":"customer","do":"wait","ms":75000,"since":"delivery-start-accepted"},{"actor":"customer","do":"reload","settleMs":1000},{"actor":"customer","do":"ensureSignedIn","name":"durable-delivery","readyTestid":"current-user"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"customer","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"customer","do":"expect","ignoreCase":true,"in":{"contains":"Keyboard","testid":"order-item"},"testid":"order-status","value":"delivered","within":10000}]}],"id":315,"setup":[{"actor":"customer","do":"signUp","name":"durable-delivery"},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"staff","do":"click","testid":"staff-link"},{"actor":"customer","do":"click","in":{"contains":"Keyboard","testid":"item-card"},"testid":"buy-now"},{"actor":"staff","do":"reload","settleMs":1000},{"actor":"staff","do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026","readyTestid":"current-user"},{"actor":"staff","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"staff","do":"click","testid":"staff-link","unlessVisible":"queue-item"},{"actor":"staff","contains":"Keyboard","do":"expect","testid":"queue-item","within":10000},{"actor":"staff","do":"click","in":{"contains":"Keyboard","testid":"queue-item"},"testid":"ship-submit"},{"actor":"customer","do":"reload","settleMs":1000},{"actor":"customer","do":"ensureSignedIn","name":"durable-delivery","readyTestid":"current-user"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"customer","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"customer","do":"expect","ignoreCase":true,"in":{"contains":"Keyboard","testid":"order-item"},"testid":"order-status","value":"shipped","within":10000},{"as":"delivery-start-accepted","do":"recordTime"},{"actor":"customer","do":"wait","ms":20000},{"do":"restartBackend","settleMs":15000},{"actor":"customer","do":"reload","settleMs":3000},{"actor":"customer","do":"ensureSignedIn","name":"durable-delivery","readyTestid":"current-user"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"customer","do":"click","testid":"orders-toggle"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.l3.deferred-durability-specifications","requiresFeatures":["ecommerce.l3.order-delivery-features"],"role":"guarantee","source":"scenarios/03-deferred-durability.json","stablePackId":"ecommerce.l3.deferred-durability"},{"checkGroupId":"restart-survival","feature":{"actors":["customer","watcher"],"criteria":[{"id":"316a","steps":[{"atMost":250000,"do":"expectElapsed","since":"pending-316"},{"actor":"customer","do":"reload","settleMs":1000},{"actor":"customer","do":"ensureSignedIn","name":"durable-cart","readyTestid":"current-user"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"customer","do":"click","testid":"cart-toggle","unlessVisible":"cart-item"},{"atMost":250000,"do":"expectElapsed","since":"pending-316"},{"actor":"customer","do":"expectNumber","equals":1,"testid":"cart-count","within":1000},{"atMost":250000,"do":"expectElapsed","since":"pending-316"},{"actor":"customer","do":"wait","ms":310000,"since":"pending-316-accepted"},{"actor":"customer","do":"reload","settleMs":3000},{"actor":"customer","do":"ensureSignedIn","name":"durable-cart","readyTestid":"current-user"},{"actor":"customer","do":"click","testid":"cart-toggle"},{"actor":"customer","do":"expectNumber","equals":0,"testid":"cart-count","within":10000},{"actor":"customer","do":"expect","testid":"cart-expired-notice","within":10000},{"actor":"watcher","do":"reload","settleMs":1000},{"actor":"watcher","do":"expectNumber","in":{"contains":"Bluetooth Speaker","testid":"item-card"},"plus":0,"relativeTo":"before","testid":"item-stock","within":10000}]}],"id":316,"setup":[{"actor":"customer","do":"signUp","name":"durable-cart"},{"actor":"watcher","as":"before","do":"recordNumber","in":{"contains":"Bluetooth Speaker","testid":"item-card"},"testid":"item-stock"},{"as":"pending-316","do":"recordTime"},{"actor":"customer","do":"click","in":{"contains":"Bluetooth Speaker","testid":"item-card"},"testid":"add-to-cart"},{"actor":"watcher","do":"reload","settleMs":1000},{"actor":"watcher","do":"expectNumber","in":{"contains":"Bluetooth Speaker","testid":"item-card"},"plus":-1,"relativeTo":"before","testid":"item-stock","within":10000},{"as":"pending-316-accepted","do":"recordTime"},{"actor":"customer","do":"wait","ms":120000},{"do":"restartBackend","settleMs":15000},{"actor":"watcher","do":"reload","settleMs":3000}]},"observations":["requested","unmentioned"],"packId":"ecommerce.l3.deferred-durability-specifications","requiresFeatures":["ecommerce.l3.cart-expiration-features"],"role":"guarantee","source":"scenarios/03-deferred-durability.json","stablePackId":"ecommerce.l3.deferred-durability"}],"id":"selected-source-052","scenario":{"level":3,"writeUrlPattern":null},"source":"scenarios/03-deferred-durability.json"},{"checkGroups":[{"checkGroupId":"exactly-once","feature":{"actors":["admin","watcher"],"criteria":[{"id":"311a","steps":[{"actor":"watcher","do":"reload","settleMs":2000},{"do":"dbExpectStock","item":"Air Purifier","plus":5,"relativeTo":"before","within":45000},{"do":"restartBackend","settleMs":15000},{"actor":"watcher","do":"reload","settleMs":3000},{"actor":"watcher","do":"wait","ms":15000},{"do":"dbExpectStock","item":"Air Purifier","plus":5,"relativeTo":"before"}]}],"id":311,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"click","testid":"admin-link"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"restocks-link"},{"as":"before","do":"dbRecordStock","item":"Air Purifier"},{"actor":"admin","do":"fill","testid":"schedule-restock-item","text":"Air Purifier"},{"actor":"admin","do":"fill","testid":"schedule-restock-warehouse","text":"East"},{"actor":"admin","do":"fill","testid":"schedule-restock-qty","text":"5"},{"actor":"admin","do":"fill","testid":"schedule-restock-delay","text":"20"},{"actor":"admin","do":"click","testid":"schedule-restock-submit"},{"actor":"admin","count":1,"do":"expect","testid":"pending-restock-item","within":10000},{"do":"dbExpectStock","item":"Air Purifier","plus":0,"relativeTo":"before"},{"do":"restartBackend","settleMs":15000},{"actor":"watcher","do":"reload","settleMs":3000}]},"observations":["requested","unmentioned"],"packId":"ecommerce.l3.deferred-integrity-specifications","requiresFeatures":["ecommerce.l3.scheduled-restocks-features"],"role":"guarantee","source":"scenarios/03-deferred-integrity.json","stablePackId":"ecommerce.l3.deferred-integrity"},{"checkGroupId":"exactly-once","feature":{"actors":["customer","staff"],"criteria":[{"id":"312a","steps":[{"actor":"staff","do":"reload","settleMs":2000},{"actor":"staff","do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026","readyTestid":"current-user"},{"actor":"staff","do":"click","ifAvailable":true,"testid":"staff-link"},{"actor":"staff","contains":"Desk Lamp","count":1,"do":"expect","testid":"completed-order-item"},{"actor":"staff","do":"expect","ignoreCase":true,"in":{"contains":"Desk Lamp","testid":"completed-order-item"},"testid":"completed-order-status","value":"delivered"}]}],"id":312,"setup":[{"actor":"customer","do":"signUp","name":"once-delivery"},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"staff","do":"click","testid":"staff-link"},{"actor":"customer","do":"click","in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"buy-now"},{"actor":"staff","do":"reload","settleMs":1000},{"actor":"staff","do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026","readyTestid":"current-user"},{"actor":"staff","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"staff","do":"click","testid":"staff-link","unlessVisible":"queue-item"},{"actor":"staff","contains":"Desk Lamp","do":"expect","testid":"queue-item","within":10000},{"actor":"staff","do":"click","in":{"contains":"Desk Lamp","testid":"queue-item"},"testid":"ship-submit"},{"actor":"customer","do":"reload","settleMs":1000},{"actor":"customer","do":"ensureSignedIn","name":"once-delivery","readyTestid":"current-user"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"customer","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"customer","do":"expect","ignoreCase":true,"in":{"contains":"Desk Lamp","testid":"order-item"},"testid":"order-status","value":"shipped","within":10000},{"actor":"customer","do":"wait","ms":70000},{"actor":"customer","do":"reload","settleMs":1000},{"actor":"customer","do":"ensureSignedIn","name":"once-delivery","readyTestid":"current-user"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"customer","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"customer","do":"expect","ignoreCase":true,"in":{"contains":"Desk Lamp","testid":"order-item"},"testid":"order-status","value":"delivered","within":15000},{"do":"restartBackend","settleMs":15000},{"actor":"staff","do":"reload","settleMs":3000},{"actor":"staff","do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026","readyTestid":"current-user"},{"actor":"staff","do":"click","ifAvailable":true,"testid":"staff-link","within":1000}]},"observations":["requested","unmentioned"],"packId":"ecommerce.l3.deferred-integrity-specifications","requiresFeatures":["ecommerce.l3.order-delivery-features"],"role":"guarantee","source":"scenarios/03-deferred-integrity.json","stablePackId":"ecommerce.l3.deferred-integrity"},{"checkGroupId":"stock-conservation","feature":{"actors":["customer","watcher"],"criteria":[{"id":"313a","steps":[{"actor":"watcher","do":"wait","ms":100000},{"actor":"watcher","do":"reload","settleMs":1000},{"actor":"watcher","do":"expectNumber","in":{"contains":"Keyboard","testid":"item-card"},"plus":0,"relativeTo":"before","testid":"item-stock","within":30000}]}],"id":313,"setup":[{"actor":"customer","do":"signUp","name":"conserve-expiry"},{"actor":"watcher","as":"before","do":"recordNumber","in":{"contains":"Keyboard","testid":"item-card"},"testid":"item-stock"},{"actor":"customer","do":"click","in":{"contains":"Keyboard","testid":"item-card"},"testid":"add-to-cart"},{"actor":"watcher","do":"reload","settleMs":1000},{"actor":"watcher","do":"expectNumber","in":{"contains":"Keyboard","testid":"item-card"},"plus":-1,"relativeTo":"before","testid":"item-stock","within":10000}]},"observations":["requested","unmentioned"],"packId":"ecommerce.l3.deferred-integrity-specifications","requiresFeatures":["ecommerce.l3.reservations-features"],"role":"guarantee","source":"scenarios/03-deferred-integrity.json","stablePackId":"ecommerce.l3.deferred-integrity"},{"checkGroupId":"stock-conservation","feature":{"actors":["customer","watcher"],"criteria":[{"id":"314a","steps":[{"actor":"customer","do":"click","testid":"checkout-submit"},{"actor":"customer","do":"expectNumber","equals":0,"testid":"cart-count","within":10000},{"actor":"customer","do":"reload","settleMs":1000},{"actor":"customer","do":"ensureSignedIn","name":"conserve-checkout","readyTestid":"current-user"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"customer","do":"click","testid":"orders-toggle"},{"actor":"customer","contains":"Headphones","do":"expectElementCount","equals":1,"testid":"order-item","within":10000},{"actor":"watcher","do":"reload","settleMs":1000},{"actor":"watcher","do":"expectNumber","in":{"contains":"Headphones","testid":"item-card"},"plus":-1,"relativeTo":"before","testid":"item-stock","within":10000}]}],"id":314,"setup":[{"actor":"customer","do":"signUp","name":"conserve-checkout"},{"actor":"watcher","as":"before","do":"recordNumber","in":{"contains":"Headphones","testid":"item-card"},"testid":"item-stock"},{"actor":"customer","do":"click","in":{"contains":"Headphones","testid":"item-card"},"testid":"add-to-cart"},{"actor":"customer","do":"click","testid":"cart-toggle"},{"actor":"watcher","do":"reload","settleMs":1000},{"actor":"watcher","do":"expectNumber","in":{"contains":"Headphones","testid":"item-card"},"plus":-1,"relativeTo":"before","testid":"item-stock","within":10000}]},"observations":["requested","unmentioned"],"packId":"ecommerce.l3.deferred-integrity-specifications","requiresFeatures":["ecommerce.l3.reservations-features"],"role":"guarantee","source":"scenarios/03-deferred-integrity.json","stablePackId":"ecommerce.l3.deferred-integrity"}],"id":"selected-source-053","scenario":{"level":3,"writeUrlPattern":null},"source":"scenarios/03-deferred-integrity.json"},{"checkGroups":[{"checkGroupId":"order-delivery","feature":{"actors":["customer","staff"],"criteria":[{"id":"303a","steps":[{"actor":"customer","do":"wait","ms":70000},{"actor":"customer","do":"reload","settleMs":1000},{"actor":"customer","do":"ensureSignedIn","name":"delivery-live","readyTestid":"current-user"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"customer","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"customer","do":"expect","ignoreCase":true,"in":{"contains":"Gaming Mouse","testid":"order-item"},"testid":"order-status","value":"delivered","within":15000},{"actor":"staff","do":"reload","settleMs":1000},{"actor":"staff","do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026","readyTestid":"current-user"},{"actor":"staff","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"staff","do":"click","testid":"staff-link","unlessVisible":"completed-order-item"},{"actor":"staff","do":"expect","ignoreCase":true,"in":{"contains":"Gaming Mouse","testid":"completed-order-item"},"testid":"completed-order-status","value":"delivered","within":15000}]}],"id":303,"setup":[{"actor":"customer","do":"signUp","name":"delivery-live"},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"staff","do":"click","testid":"staff-link"},{"actor":"customer","do":"click","in":{"contains":"Gaming Mouse","testid":"item-card"},"testid":"buy-now"},{"actor":"staff","do":"reload","settleMs":1000},{"actor":"staff","do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026","readyTestid":"current-user"},{"actor":"staff","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"staff","do":"click","testid":"staff-link","unlessVisible":"queue-item"},{"actor":"staff","contains":"Gaming Mouse","do":"expect","testid":"queue-item","within":10000},{"actor":"staff","do":"click","in":{"contains":"Gaming Mouse","testid":"queue-item"},"testid":"ship-submit"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"customer","do":"reload","settleMs":1000},{"actor":"customer","do":"ensureSignedIn","name":"delivery-live","readyTestid":"current-user"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"customer","do":"click","testid":"orders-toggle"},{"actor":"customer","do":"expect","ignoreCase":true,"in":{"contains":"Gaming Mouse","testid":"order-item"},"testid":"order-status","value":"shipped","within":10000}]},"packId":"ecommerce.l3.order-delivery-features","role":"feature","source":"scenarios/03-order-delivery.json","stablePackId":"ecommerce.l3.order-delivery"},{"checkGroupId":"order-delivery","feature":{"actors":["customer"],"criteria":[{"id":"305a","steps":[{"actor":"customer","do":"wait","ms":70000},{"actor":"customer","do":"reload","settleMs":1000},{"actor":"customer","do":"ensureSignedIn","name":"delivery-cancel","readyTestid":"current-user"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"customer","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"customer","do":"expect","ignoreCase":true,"in":{"contains":"Keyboard","testid":"order-item"},"testid":"order-status","value":"cancelled"}]}],"id":305,"setup":[{"actor":"customer","do":"signUp","name":"delivery-cancel"},{"actor":"customer","do":"click","in":{"contains":"Keyboard","testid":"item-card"},"testid":"buy-now"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"customer","do":"click","testid":"orders-toggle"},{"actor":"customer","do":"click","in":{"contains":"Keyboard","testid":"order-item"},"testid":"cancel-order"},{"actor":"customer","do":"expect","ignoreCase":true,"in":{"contains":"Keyboard","testid":"order-item"},"testid":"order-status","value":"cancelled","within":10000}]},"packId":"ecommerce.l3.order-delivery-features","role":"feature","source":"scenarios/03-order-delivery.json","stablePackId":"ecommerce.l3.order-delivery"}],"id":"selected-source-054","scenario":{"level":3,"writeUrlPattern":null},"source":"scenarios/03-order-delivery.json"},{"checkGroups":[{"checkGroupId":"reservations","feature":{"actors":["shopper","watcher"],"criteria":[{"id":"301a","steps":[{"actor":"shopper","do":"click","in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"add-to-cart"},{"actor":"watcher","do":"expectNumber","in":{"contains":"Desk Lamp","testid":"item-card"},"plus":-1,"relativeTo":"before","testid":"item-stock","within":10000}]}],"id":301,"setup":[{"actor":"shopper","do":"signUp","name":"reserve-stock"},{"actor":"watcher","as":"before","do":"recordNumber","in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"item-stock"}]},"packId":"ecommerce.l3.reservations-features","role":"feature","source":"scenarios/03-reservations.json","stablePackId":"ecommerce.l3.reservations"},{"checkGroupId":"reservations","feature":{"actors":["shopper"],"criteria":[{"id":"305a","steps":[{"actor":"shopper","atLeast":1,"atMost":90,"do":"expectNumber","in":{"contains":"Gaming Mouse","testid":"cart-item"},"testid":"cart-reservation-timer"},{"actor":"shopper","as":"initial-countdown","do":"recordNumber","in":{"contains":"Gaming Mouse","testid":"cart-item"},"testid":"cart-reservation-timer"},{"actor":"shopper","do":"wait","ms":1000},{"actor":"shopper","comparison":"atMost","do":"expectNumber","in":{"contains":"Gaming Mouse","testid":"cart-item"},"plus":-1,"relativeTo":"initial-countdown","testid":"cart-reservation-timer","within":10000}]}],"id":305,"setup":[{"actor":"shopper","do":"signUp","name":"reserve-clock"},{"actor":"shopper","do":"click","in":{"contains":"Gaming Mouse","testid":"item-card"},"testid":"add-to-cart"},{"actor":"shopper","do":"click","testid":"cart-toggle"}]},"packId":"ecommerce.l3.reservations-features","role":"feature","source":"scenarios/03-reservations.json","stablePackId":"ecommerce.l3.reservations"},{"checkGroupId":"reservations","feature":{"actors":["shopper"],"criteria":[{"id":"306a","steps":[{"actor":"shopper","do":"click","testid":"checkout-submit"},{"actor":"shopper","do":"expectNumber","equals":0,"testid":"cart-count","within":10000},{"actor":"shopper","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"shopper","do":"click","testid":"orders-toggle"},{"actor":"shopper","contains":"Keyboard","count":1,"do":"expect","testid":"order-item"}]}],"id":306,"setup":[{"actor":"shopper","do":"signUp","name":"reserve-checkout"},{"actor":"shopper","do":"click","in":{"contains":"Keyboard","testid":"item-card"},"testid":"add-to-cart"},{"actor":"shopper","do":"click","testid":"cart-toggle"}]},"packId":"ecommerce.l3.reservations-features","role":"feature","source":"scenarios/03-reservations.json","stablePackId":"ecommerce.l3.reservations"},{"checkGroupId":"reservations","feature":{"actors":["shopper"],"criteria":[{"id":"307a","steps":[{"actor":"shopper","do":"wait","ms":100000},{"actor":"shopper","do":"expect","in":{"contains":"Bluetooth Speaker","testid":"cart-item"},"testid":"cart-item-expired","within":15000}]}],"id":307,"setup":[{"actor":"shopper","do":"signUp","name":"reserve-expiry"},{"actor":"shopper","do":"click","in":{"contains":"Bluetooth Speaker","testid":"item-card"},"testid":"add-to-cart"},{"actor":"shopper","do":"click","testid":"cart-toggle"}]},"packId":"ecommerce.l3.reservations-features","role":"feature","source":"scenarios/03-reservations.json","stablePackId":"ecommerce.l3.reservations"},{"checkGroupId":"reservations","feature":{"actors":["shopper"],"criteria":[{"id":"308a","steps":[{"actor":"shopper","do":"wait","ms":40000},{"actor":"shopper","atLeast":35,"do":"expectNumber","in":{"contains":"Headphones","testid":"cart-item"},"testid":"cart-reservation-timer"},{"absent":true,"actor":"shopper","do":"expect","in":{"contains":"Headphones","testid":"cart-item"},"testid":"cart-item-expired"}]}],"id":308,"setup":[{"actor":"shopper","do":"signUp","name":"reserve-renew"},{"actor":"shopper","do":"click","in":{"contains":"Headphones","testid":"item-card"},"testid":"add-to-cart"},{"actor":"shopper","do":"wait","ms":60000},{"actor":"shopper","do":"click","in":{"contains":"Headphones","testid":"item-card"},"testid":"add-to-cart"},{"actor":"shopper","do":"click","testid":"cart-toggle"}]},"packId":"ecommerce.l3.reservations-features","role":"feature","source":"scenarios/03-reservations.json","stablePackId":"ecommerce.l3.reservations"}],"id":"selected-source-055","scenario":{"level":3,"writeUrlPattern":null},"source":"scenarios/03-reservations.json"},{"checkGroups":[{"checkGroupId":"scheduled-restocks","feature":{"actors":["admin","watcher"],"criteria":[{"id":"305a","steps":[{"actor":"admin","as":"ledger-before","count":true,"do":"recordNumber","testid":"stock-ledger-entry"},{"actor":"admin","do":"fill","testid":"schedule-restock-item","text":"Keyboard"},{"actor":"admin","do":"fill","testid":"schedule-restock-warehouse","text":"West"},{"actor":"admin","do":"fill","testid":"schedule-restock-qty","text":"7"},{"actor":"admin","do":"fill","testid":"schedule-restock-delay","text":"15"},{"actor":"admin","do":"click","testid":"schedule-restock-submit"},{"actor":"admin","do":"wait","ms":25000},{"actor":"watcher","do":"reload","settleMs":2000},{"actor":"admin","do":"reload","settleMs":2000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"admin-link"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"restocks-link"},{"actor":"watcher","do":"expectNumber","in":{"contains":"Keyboard","testid":"item-card"},"plus":7,"relativeTo":"before","testid":"item-stock","within":15000},{"absent":true,"actor":"admin","do":"expect","testid":"pending-restock-item"},{"actor":"admin","do":"expectElementCount","plus":1,"relativeTo":"ledger-before","testid":"stock-ledger-entry"}]}],"id":305,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"click","testid":"admin-link"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"restocks-link"},{"actor":"watcher","as":"before","do":"recordNumber","in":{"contains":"Keyboard","testid":"item-card"},"testid":"item-stock"}]},"packId":"ecommerce.l3.scheduled-restocks-features","role":"feature","source":"scenarios/03-scheduled-restock-apply.json","stablePackId":"ecommerce.l3.scheduled-restocks"}],"id":"selected-source-056","scenario":{"level":3,"writeUrlPattern":null},"source":"scenarios/03-scheduled-restock-apply.json"},{"checkGroups":[{"checkGroupId":"scheduled-restocks","feature":{"actors":["admin","watcher"],"criteria":[{"id":"306a","steps":[{"actor":"admin","do":"fill","testid":"schedule-restock-item","text":"Desk Lamp"},{"actor":"admin","do":"fill","testid":"schedule-restock-warehouse","text":"East"},{"actor":"admin","do":"fill","testid":"schedule-restock-qty","text":"9"},{"actor":"admin","do":"fill","testid":"schedule-restock-delay","text":"15"},{"actor":"admin","do":"click","testid":"schedule-restock-submit"},{"actor":"admin","count":1,"do":"expect","testid":"pending-restock-item"},{"actor":"admin","do":"click","in":{"testid":"pending-restock-item"},"testid":"pending-restock-cancel"},{"actor":"admin","do":"wait","ms":25000},{"actor":"watcher","do":"reload","settleMs":2000},{"actor":"watcher","do":"expectNumber","in":{"contains":"Desk Lamp","testid":"item-card"},"plus":0,"relativeTo":"before","testid":"item-stock"}]}],"id":306,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"click","testid":"admin-link"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"restocks-link"},{"actor":"watcher","as":"before","do":"recordNumber","in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"item-stock"}]},"packId":"ecommerce.l3.scheduled-restocks-features","role":"feature","source":"scenarios/03-scheduled-restock-cancel.json","stablePackId":"ecommerce.l3.scheduled-restocks"}],"id":"selected-source-057","scenario":{"level":3,"writeUrlPattern":null},"source":"scenarios/03-scheduled-restock-cancel.json"},{"checkGroups":[{"checkGroupId":"scheduled-restocks","feature":{"actors":["admin"],"criteria":[{"id":"302a","steps":[{"actor":"admin","do":"fill","testid":"schedule-restock-item","text":"Webcam"},{"actor":"admin","do":"fill","testid":"schedule-restock-warehouse","text":"East"},{"actor":"admin","do":"fill","testid":"schedule-restock-qty","text":"7"},{"actor":"admin","do":"fill","testid":"schedule-restock-delay","text":"90"},{"actor":"admin","do":"click","testid":"schedule-restock-submit"},{"actor":"admin","count":1,"do":"expect","testid":"pending-restock-item","within":10000},{"actor":"admin","atLeast":1,"atMost":90,"do":"expectNumber","in":{"testid":"pending-restock-item"},"testid":"pending-restock-remaining"},{"actor":"admin","as":"initial-countdown","do":"recordNumber","in":{"testid":"pending-restock-item"},"testid":"pending-restock-remaining"},{"actor":"admin","do":"wait","ms":1000},{"actor":"admin","comparison":"atMost","do":"expectNumber","in":{"testid":"pending-restock-item"},"plus":-1,"relativeTo":"initial-countdown","testid":"pending-restock-remaining","within":10000},{"actor":"admin","do":"click","in":{"testid":"pending-restock-item"},"testid":"pending-restock-cancel"}]}],"id":302,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"click","testid":"admin-link"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"restocks-link"}]},"packId":"ecommerce.l3.scheduled-restocks-features","role":"feature","source":"scenarios/03-scheduled-restocks.json","stablePackId":"ecommerce.l3.scheduled-restocks"}],"id":"selected-source-058","scenario":{"level":3,"writeUrlPattern":null},"source":"scenarios/03-scheduled-restocks.json"},{"checkGroups":[{"checkGroupId":"server-time","feature":{"actors":["admin","watcher"],"criteria":[{"id":"312a","steps":[{"actor":"watcher","do":"wait","ms":30000},{"actor":"watcher","do":"reload","settleMs":2000},{"atMost":100000,"do":"expectElapsed","since":"restock-start"},{"do":"dbExpectStock","item":"Espresso Machine","plus":0,"relativeTo":"before"},{"actor":"admin","count":1,"do":"expect","testid":"pending-restock-item"},{"atMost":100000,"do":"expectElapsed","since":"restock-start"},{"actor":"admin","do":"wait","ms":130000,"since":"restock-start-accepted"},{"do":"dbExpectStock","item":"Espresso Machine","plus":4,"relativeTo":"before","within":10000},{"actor":"admin","do":"reload","settleMs":2000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"admin-link","within":1000},{"actor":"admin","do":"click","ifAvailable":true,"testid":"restocks-link","within":1000},{"actor":"admin","do":"expect","testid":"schedule-restock-submit"},{"absent":true,"actor":"admin","do":"expect","testid":"pending-restock-item"}]}],"id":312,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"click","testid":"admin-link"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"restocks-link","within":1000},{"as":"before","do":"dbRecordStock","item":"Espresso Machine"},{"actor":"admin","do":"fill","testid":"schedule-restock-item","text":"Espresso Machine"},{"actor":"admin","do":"fill","testid":"schedule-restock-warehouse","text":"West"},{"actor":"admin","do":"fill","testid":"schedule-restock-qty","text":"4"},{"actor":"admin","do":"fill","testid":"schedule-restock-delay","text":"120"},{"as":"restock-start","do":"recordTime"},{"actor":"admin","do":"click","testid":"schedule-restock-submit"},{"actor":"admin","count":1,"do":"expect","testid":"pending-restock-item","within":10000},{"as":"restock-start-accepted","do":"recordTime"},{"do":"dbExpectStock","item":"Espresso Machine","plus":0,"relativeTo":"before"},{"do":"restartBackend","settleMs":15000},{"actor":"watcher","do":"reload","settleMs":3000},{"actor":"admin","do":"reload","settleMs":3000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"admin-link","within":1000},{"actor":"admin","do":"click","ifAvailable":true,"testid":"restocks-link","within":1000},{"actor":"admin","do":"expect","testid":"schedule-restock-submit"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.l3.server-time-specifications","requiresFeatures":["ecommerce.l3.scheduled-restocks-features"],"role":"guarantee","source":"scenarios/03-server-time.json","stablePackId":"ecommerce.l3.server-time"},{"checkGroupId":"server-time","feature":{"actors":["customer","watcher"],"criteria":[{"id":"313a","steps":[{"actor":"watcher","do":"wait","ms":100000},{"actor":"watcher","do":"reload","settleMs":1000},{"actor":"watcher","do":"expectNumber","in":{"contains":"Air Purifier","testid":"item-card"},"plus":0,"relativeTo":"before","testid":"item-stock","within":30000}]}],"id":313,"setup":[{"actor":"customer","do":"signUp","name":"server-clock"},{"actor":"watcher","as":"before","do":"recordNumber","in":{"contains":"Air Purifier","testid":"item-card"},"testid":"item-stock"},{"actor":"customer","do":"click","in":{"contains":"Air Purifier","testid":"item-card"},"testid":"add-to-cart"},{"actor":"watcher","do":"reload","settleMs":1000},{"actor":"watcher","do":"expectNumber","in":{"contains":"Air Purifier","testid":"item-card"},"plus":-1,"relativeTo":"before","testid":"item-stock","within":10000},{"actor":"customer","do":"closeClient"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.l3.server-time-specifications","requiresFeatures":["ecommerce.l3.reservations-features"],"role":"guarantee","source":"scenarios/03-server-time.json","stablePackId":"ecommerce.l3.server-time"}],"id":"selected-source-059","scenario":{"level":3,"writeUrlPattern":null},"source":"scenarios/03-server-time.json"},{"checkGroups":[{"checkGroupId":"account-state-recovery","feature":{"actors":["shopper","peer"],"criteria":[{"id":"105b","steps":[{"actor":"shopper","do":"setOffline","offline":true,"settleMs":3000},{"actor":"peer","do":"click","in":{"contains":"Headphones","testid":"item-card"},"testid":"add-to-cart"},{"actor":"shopper","do":"setOffline","offline":false,"settleMs":6000},{"actor":"shopper","contains":"pat","do":"expect","testid":"current-user"},{"actor":"shopper","do":"click","testid":"cart-toggle","unlessVisible":"cart-total"},{"actor":"shopper","contains":"Keyboard","do":"expect","testid":"cart-item"},{"actor":"shopper","contains":"Headphones","do":"expect","testid":"cart-item"}]}],"id":105,"setup":[{"actor":"shopper","do":"signUp","name":"pat"},{"actor":"peer","do":"signIn","name":"pat"},{"actor":"shopper","do":"click","in":{"contains":"Keyboard","testid":"item-card"},"testid":"add-to-cart"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.state-durability","requiresFeatures":["ecommerce.feature.accounts","ecommerce.feature.checkout"],"role":"guarantee","source":"scenarios/progression-account-state-reconnect.json"}],"id":"selected-source-060","scenario":{"level":1,"writeUrlPattern":null},"source":"scenarios/progression-account-state-reconnect.json"},{"checkGroups":[{"checkGroupId":"account-state-recovery","feature":{"actors":["shopper"],"criteria":[{"id":"105a","steps":[{"actor":"shopper","do":"click","in":{"contains":"Headphones","testid":"item-card"},"testid":"add-to-cart"},{"actor":"shopper","do":"click","testid":"cart-toggle","unlessVisible":"cart-total"},{"actor":"shopper","do":"click","settleMs":1500,"testid":"checkout-submit"},{"actor":"shopper","do":"click","ifAvailable":true,"testid":"overlay-close"},{"actor":"shopper","do":"click","ifAvailable":true,"settleMs":2500,"testid":"catalog-link"},{"actor":"shopper","do":"click","in":{"contains":"Keyboard","testid":"item-card"},"testid":"add-to-cart"},{"actor":"shopper","do":"click","testid":"cart-toggle","unlessVisible":"cart-total"},{"actor":"shopper","contains":"Keyboard","do":"expect","testid":"cart-item","within":10000},{"actor":"shopper","do":"reload","settleMs":4000},{"actor":"shopper","contains":"pat","do":"expect","testid":"current-user"},{"actor":"shopper","do":"click","testid":"cart-toggle","unlessVisible":"cart-total"},{"actor":"shopper","contains":"Keyboard","do":"expect","testid":"cart-item"},{"actor":"shopper","do":"reload","settleMs":2500},{"actor":"shopper","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"shopper","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"shopper","contains":"Headphones","count":1,"do":"expect","testid":"order-item"},{"do":"restartBackend","settleMs":1000},{"actor":"shopper","do":"freshClient"},{"actor":"shopper-fresh","do":"signIn","name":"pat"},{"actor":"shopper-fresh","do":"click","testid":"cart-toggle","unlessVisible":"cart-total"},{"actor":"shopper-fresh","contains":"Keyboard","count":1,"do":"expect","testid":"cart-item"},{"actor":"shopper-fresh","do":"click","ifAvailable":true,"testid":"overlay-close"},{"actor":"shopper-fresh","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"shopper-fresh","contains":"Headphones","count":1,"do":"expect","testid":"order-item"}]}],"id":105,"setup":[{"actor":"shopper","do":"signUp","name":"pat"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.state-durability","requiresFeatures":["ecommerce.feature.accounts","ecommerce.feature.checkout"],"role":"guarantee","source":"scenarios/progression-account-state-reload.json"}],"id":"selected-source-061","scenario":{"level":1,"writeUrlPattern":null},"source":"scenarios/progression-account-state-reload.json"},{"checkGroups":[{"checkGroupId":"automatic-reorder-access","feature":{"actors":["staff","customer"],"criteria":[{"id":"502c","steps":[{"absent":true,"actor":"customer","do":"expect","testid":"reorder-link"},{"actor":"staff","do":"fill","testid":"reorder-item","text":"Desk Lamp"},{"actor":"staff","do":"fill","testid":"reorder-threshold","text":"1"},{"actor":"staff","do":"fill","testid":"reorder-quantity","text":"9"},{"action":"saveReorderRule","actor":"customer","do":"callAction","from":"staff","input":{"attribute":"data-action-input","testid":"reorder-submit"},"namedAction":{"args":[0,1,9],"id":"saveReorderRule","method":"PUT","params":[{"in":"path","name":"itemId","placeholder":"{itemId}","wireType":"u64"},{"in":"body","name":"threshold"},{"in":"body","name":"quantity"}],"path":"/api/reorders/{itemId}","reducer":"save_reorder_rule"}},{"actor":"customer","do":"expectActionOutcome","outcome":"refused","routeProvenBy":"staff"},{"actor":"staff","do":"reload","settleMs":1000},{"actor":"staff","do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026","readyTestid":"current-user"},{"actor":"staff","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"staff","do":"click","testid":"reorder-link","unlessVisible":"reorder-submit"},{"actor":"staff","attribute":"data-threshold","contains":"Desk Lamp","count":1,"do":"expect","testid":"reorder-rule-item","value":"2"},{"actor":"staff","attribute":"data-quantity","contains":"Desk Lamp","do":"expect","testid":"reorder-rule-item","value":"5"}]}],"id":502,"setup":[{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"staff","do":"expect","testid":"reorder-link","within":6000},{"actor":"staff","do":"click","testid":"reorder-link"},{"actor":"staff","do":"fill","testid":"reorder-item","text":"Desk Lamp"},{"actor":"staff","do":"fill","testid":"reorder-threshold","text":"2"},{"actor":"staff","do":"fill","testid":"reorder-quantity","text":"5"},{"action":"saveReorderRule","actor":"staff","do":"callAction","input":{"attribute":"data-action-input","testid":"reorder-submit"},"namedAction":{"args":[0,2,5],"id":"saveReorderRule","method":"PUT","params":[{"in":"path","name":"itemId","placeholder":"{itemId}","wireType":"u64"},{"in":"body","name":"threshold"},{"in":"body","name":"quantity"}],"path":"/api/reorders/{itemId}","reducer":"save_reorder_rule"}},{"actor":"staff","do":"expectActionOutcome","outcome":"accepted"},{"actor":"staff","do":"reload","settleMs":1000},{"actor":"staff","do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026","readyTestid":"current-user"},{"actor":"staff","do":"click","testid":"reorder-link","unlessVisible":"reorder-submit"},{"actor":"staff","contains":"Desk Lamp","do":"expectElementCount","equals":1,"testid":"reorder-rule-item","within":10000},{"actor":"customer","do":"signUp","name":"reorder-customer"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","requiresFeatures":["ecommerce.progression.automatic-reorder"],"role":"guarantee","source":"scenarios/progression-automatic-reorder-access.json"}],"id":"selected-source-062","scenario":{"level":5,"writeUrlPattern":null},"source":"scenarios/progression-automatic-reorder-access.json"},{"checkGroups":[{"checkGroupId":"automatic-reorder-deduplication","feature":{"actors":["staff","admin","buyer-a","buyer-b","buyer-c"],"criteria":[{"id":"502b","steps":[{"action":"buy","actor":"buyer-b","do":"callAction","input":{"attribute":"data-buy-input","contains":"Desk Lamp","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"}},{"actor":"buyer-b","do":"expectActionOutcome","outcome":"accepted"},{"action":"buy","actor":"buyer-c","do":"callAction","input":{"attribute":"data-buy-input","contains":"Desk Lamp","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"}},{"actor":"buyer-c","do":"expectActionOutcome","outcome":"accepted"},{"do":"dbExpectStock","equals":0,"item":"Desk Lamp"},{"actor":"admin","do":"reload","settleMs":1000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"admin","do":"click","testid":"admin-link","unlessVisible":"admin-revenue"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"restocks-link","within":1000},{"actor":"admin","do":"expect","testid":"schedule-restock-submit"},{"actor":"admin","do":"expectElementCount","equals":1,"testid":"pending-restock-item","within":10000},{"actor":"admin","attribute":"data-quantity","contains":"Desk Lamp","count":1,"do":"expect","testid":"pending-restock-item","value":"5"}]}],"id":502,"setup":[{"do":"dbSetStock","item":"Desk Lamp","quantity":2,"settleMs":2000,"warehouse":"East"},{"do":"dbSetStock","item":"Desk Lamp","quantity":1,"settleMs":2000,"warehouse":"West"},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"staff","do":"expect","testid":"reorder-link","within":6000},{"actor":"staff","do":"click","testid":"reorder-link"},{"actor":"staff","do":"fill","testid":"reorder-item","text":"Desk Lamp"},{"actor":"staff","do":"fill","testid":"reorder-threshold","text":"2"},{"actor":"staff","do":"fill","testid":"reorder-quantity","text":"5"},{"action":"saveReorderRule","actor":"staff","do":"callAction","input":{"attribute":"data-action-input","testid":"reorder-submit"},"namedAction":{"args":[0,2,5],"id":"saveReorderRule","method":"PUT","params":[{"in":"path","name":"itemId","placeholder":"{itemId}","wireType":"u64"},{"in":"body","name":"threshold"},{"in":"body","name":"quantity"}],"path":"/api/reorders/{itemId}","reducer":"save_reorder_rule"}},{"actor":"staff","do":"expectActionOutcome","outcome":"accepted"},{"actor":"staff","do":"reload","settleMs":1000},{"actor":"staff","do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026","readyTestid":"current-user"},{"actor":"staff","do":"click","testid":"reorder-link","unlessVisible":"reorder-submit"},{"actor":"staff","contains":"Desk Lamp","do":"expectElementCount","equals":1,"testid":"reorder-rule-item","within":10000},{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"click","testid":"admin-link"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"restocks-link","within":1000},{"actor":"buyer-a","do":"signUp","name":"reorder-a"},{"actor":"buyer-b","do":"signUp","name":"reorder-b"},{"actor":"buyer-c","do":"signUp","name":"reorder-c"},{"actor":"admin","do":"reload","settleMs":1000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"admin","do":"click","testid":"admin-link","unlessVisible":"admin-revenue"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"restocks-link","within":1000},{"actor":"admin","do":"expect","testid":"schedule-restock-submit"},{"actor":"admin","do":"expectElementCount","equals":0,"testid":"pending-restock-item"},{"action":"buy","actor":"buyer-a","do":"callAction","input":{"attribute":"data-buy-input","contains":"Desk Lamp","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"}},{"actor":"buyer-a","do":"expectActionOutcome","outcome":"accepted"},{"do":"dbExpectStock","equals":2,"item":"Desk Lamp"},{"actor":"admin","do":"reload","settleMs":1000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"admin","do":"click","testid":"admin-link","unlessVisible":"admin-revenue"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"restocks-link","within":1000},{"actor":"admin","do":"expect","testid":"schedule-restock-submit"},{"actor":"admin","do":"expectElementCount","equals":1,"testid":"pending-restock-item","within":10000},{"actor":"admin","attribute":"data-quantity","contains":"Desk Lamp","count":1,"do":"expect","testid":"pending-restock-item","value":"5"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.transactional-integrity","requiresFeatures":["ecommerce.feature.purchasing","ecommerce.progression.automatic-reorder"],"role":"guarantee","source":"scenarios/progression-automatic-reorder-duplicate.json"}],"id":"selected-source-063","scenario":{"level":5,"writeUrlPattern":null},"source":"scenarios/progression-automatic-reorder-duplicate.json"},{"checkGroups":[{"checkGroupId":"automatic-reorder","feature":{"actors":["staff","admin","buyer-a"],"criteria":[{"id":"502a","steps":[{"actor":"admin","do":"reload","settleMs":1000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"admin","do":"click","testid":"admin-link","unlessVisible":"admin-revenue"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"restocks-link","within":1000},{"actor":"admin","do":"expect","testid":"schedule-restock-submit"},{"actor":"admin","do":"expectElementCount","equals":0,"testid":"pending-restock-item"},{"action":"buy","actor":"buyer-a","do":"callAction","input":{"attribute":"data-buy-input","contains":"Desk Lamp","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"}},{"actor":"buyer-a","do":"expectActionOutcome","outcome":"accepted"},{"do":"dbExpectStock","equals":2,"item":"Desk Lamp"},{"actor":"admin","do":"reload","settleMs":1000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"admin","do":"click","testid":"admin-link","unlessVisible":"admin-revenue"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"restocks-link","within":1000},{"actor":"admin","do":"expect","testid":"schedule-restock-submit"},{"actor":"admin","do":"expectElementCount","equals":1,"testid":"pending-restock-item","within":10000},{"actor":"admin","attribute":"data-quantity","contains":"Desk Lamp","count":1,"do":"expect","testid":"pending-restock-item","value":"5"}]}],"id":502,"setup":[{"do":"dbSetStock","item":"Desk Lamp","quantity":2,"settleMs":2000,"warehouse":"East"},{"do":"dbSetStock","item":"Desk Lamp","quantity":1,"settleMs":2000,"warehouse":"West"},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"staff","do":"expect","testid":"reorder-link","within":6000},{"actor":"staff","do":"click","testid":"reorder-link"},{"actor":"staff","do":"fill","testid":"reorder-item","text":"Desk Lamp"},{"actor":"staff","do":"fill","testid":"reorder-threshold","text":"2"},{"actor":"staff","do":"fill","testid":"reorder-quantity","text":"5"},{"action":"saveReorderRule","actor":"staff","do":"callAction","input":{"attribute":"data-action-input","testid":"reorder-submit"},"namedAction":{"args":[0,2,5],"id":"saveReorderRule","method":"PUT","params":[{"in":"path","name":"itemId","placeholder":"{itemId}","wireType":"u64"},{"in":"body","name":"threshold"},{"in":"body","name":"quantity"}],"path":"/api/reorders/{itemId}","reducer":"save_reorder_rule"}},{"actor":"staff","do":"expectActionOutcome","outcome":"accepted"},{"actor":"staff","do":"reload","settleMs":1000},{"actor":"staff","do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026","readyTestid":"current-user"},{"actor":"staff","do":"click","testid":"reorder-link","unlessVisible":"reorder-submit"},{"actor":"staff","contains":"Desk Lamp","do":"expectElementCount","equals":1,"testid":"reorder-rule-item","within":10000},{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"click","testid":"admin-link"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"restocks-link","within":1000},{"actor":"buyer-a","do":"signUp","name":"reorder-a"}]},"packId":"ecommerce.progression.automatic-reorder","requiresFeatures":["ecommerce.feature.purchasing"],"role":"feature","source":"scenarios/progression-automatic-reorder.json"}],"id":"selected-source-064","scenario":{"level":5,"writeUrlPattern":null},"source":"scenarios/progression-automatic-reorder.json"},{"checkGroups":[{"checkGroupId":"books-balance","feature":{"actors":["buyer","admin"],"criteria":[{"id":"107a","steps":[{"actor":"admin","do":"reload","settleMs":1000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"admin","do":"click","testid":"admin-link","unlessVisible":"admin-revenue"},{"actor":"admin","do":"expectNumber","plus":58,"relativeTo":"revenue-before","testid":"admin-revenue","within":10000}]},{"id":"107b","steps":[{"actor":"admin","do":"reload","settleMs":2000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"admin-link"},{"actor":"admin","do":"expectNumber","in":{"contains":"Laptop Stand","testid":"admin-item-row"},"plus":-2,"relativeTo":"stand-before","testid":"admin-stock"},{"actor":"buyer","do":"freshClient"},{"actor":"buyer-fresh","do":"expectNumber","in":{"contains":"Laptop Stand","testid":"item-card"},"plus":-2,"relativeTo":"stand-before","testid":"item-stock"}]}],"id":107,"setup":[{"actor":"buyer","do":"signUp","name":"sam"},{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"click","testid":"admin-link"},{"actor":"admin","as":"revenue-before","do":"recordNumber","testid":"admin-revenue"},{"actor":"admin","as":"stand-before","do":"recordNumber","in":{"contains":"Laptop Stand","testid":"admin-item-row"},"testid":"admin-stock"},{"action":"buy","actor":"buyer","do":"callAction","input":{"attribute":"data-buy-input","contains":"Laptop Stand","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"}},{"actor":"buyer","do":"expectActionOutcome","outcome":"accepted"},{"action":"buy","actor":"buyer","do":"callAction","input":{"attribute":"data-buy-input","contains":"Laptop Stand","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"}},{"actor":"buyer","do":"expectActionOutcome","outcome":"accepted"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.transactional-integrity","requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.warehouse-admin"],"role":"guarantee","source":"scenarios/progression-books-balance.json"}],"id":"selected-source-065","scenario":{"level":1,"writeUrlPattern":null},"source":"scenarios/progression-books-balance.json"},{"checkGroups":[{"checkGroupId":"bundle-checkout","feature":{"actors":["admin","buyer"],"criteria":[{"id":"741a","steps":[{"actor":"buyer","do":"click","in":{"contains":"Checkout bundle","testid":"bundle-card"},"settleMs":500,"testid":"bundle-add-to-cart"},{"do":"dbExpectStock","equals":4,"item":"Keyboard","warehouse":"East"},{"do":"dbExpectStock","equals":3,"item":"Desk Lamp","warehouse":"East"},{"actor":"buyer","do":"click","testid":"cart-toggle"},{"actor":"buyer","do":"click","testid":"checkout-submit"},{"actor":"buyer","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"buyer","do":"click","testid":"orders-toggle"},{"actor":"buyer","contains":"Checkout bundle","count":1,"do":"expect","testid":"order-item","within":10000},{"actor":"buyer","do":"expectNumber","equals":75,"in":{"contains":"Checkout bundle","testid":"order-item"},"testid":"payment-amount","within":10000},{"do":"dbExpectStock","equals":4,"item":"Keyboard","warehouse":"East"},{"do":"dbExpectStock","equals":3,"item":"Desk Lamp","warehouse":"East"},{"do":"dbExpectStock","equals":0,"item":"Keyboard","warehouse":"West"},{"do":"dbExpectStock","equals":0,"item":"Desk Lamp","warehouse":"West"}]}],"id":741,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"click","testid":"bundles-link","unlessVisible":"bundle-name-input"},{"actor":"buyer","do":"signUp","name":"bundle-checkout"},{"do":"dbSetStock","item":"Keyboard","quantity":6,"settleMs":0,"warehouse":"East"},{"do":"dbSetStock","item":"Keyboard","quantity":0,"settleMs":0,"warehouse":"West"},{"do":"dbSetStock","item":"Desk Lamp","quantity":4,"settleMs":0,"warehouse":"East"},{"do":"dbSetStock","item":"Desk Lamp","quantity":0,"settleMs":0,"warehouse":"West"},{"actor":"admin","do":"fill","testid":"bundle-name-input","text":"Checkout bundle"},{"actor":"admin","do":"fill","testid":"bundle-price-input","text":"75.00"},{"actor":"admin","do":"fill","testid":"bundle-components-input","text":"[{\"item\":\"Keyboard\",\"quantity\":2},{\"item\":\"Desk Lamp\",\"quantity\":1}]"},{"actor":"admin","do":"click","testid":"bundle-save"},{"actor":"admin","contains":"Checkout bundle","do":"expect","testid":"bundle-card","within":10000},{"actor":"buyer","do":"click","testid":"bundles-link","unlessVisible":"bundle-card"}]},"packId":"ecommerce.feature.bundle-checkout","role":"feature","source":"scenarios/progression-bundle-checkout.json"},{"checkGroupId":"bundle-744","feature":{"actors":["admin","a","b"],"criteria":[{"id":"744a","steps":[{"action":"addBundleToCart","actors":["a","b"],"do":"callConcurrently","input":{"attribute":"data-bundle-input","contains":"Scarce bundle","testid":"bundle-card"},"namedAction":{"args":[0],"id":"addBundleToCart","params":[{"in":"body","name":"bundleId","wireType":"u64"}],"path":"/api/cart/bundles","reducer":"add_bundle_to_cart"},"settleMs":1000},{"accepted":1,"do":"expectCallOutcomes"},{"do":"dbExpectStock","equals":0,"item":"Keyboard","warehouse":"East"},{"do":"dbExpectStock","equals":0,"item":"Desk Lamp","warehouse":"East"},{"actor":"a","do":"reload","settleMs":1000},{"actor":"b","do":"reload","settleMs":1000},{"actor":"a","do":"click","testid":"cart-toggle"},{"actor":"b","do":"click","testid":"cart-toggle"},{"actors":["a","b"],"contains":"Scarce bundle","do":"expectActorsWith","equals":1,"maxEach":1,"testid":"cart-item"},{"actor":"a","do":"click","ifAvailable":true,"in":{"contains":"Scarce bundle","testid":"cart-item"},"settleMs":500,"testid":"bundle-remove"},{"actor":"b","do":"click","ifAvailable":true,"in":{"contains":"Scarce bundle","testid":"cart-item"},"settleMs":500,"testid":"bundle-remove"},{"do":"dbExpectStock","equals":2,"item":"Keyboard","warehouse":"East"},{"do":"dbExpectStock","equals":1,"item":"Desk Lamp","warehouse":"East"}]}],"id":744,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"click","testid":"bundles-link","unlessVisible":"bundle-name-input"},{"actor":"a","do":"signUp","name":"bundle-race-a"},{"actor":"b","do":"signUp","name":"bundle-race-b"},{"do":"dbSetStock","item":"Keyboard","quantity":2,"settleMs":0,"warehouse":"East"},{"do":"dbSetStock","item":"Keyboard","quantity":0,"settleMs":0,"warehouse":"West"},{"do":"dbSetStock","item":"Desk Lamp","quantity":1,"settleMs":0,"warehouse":"East"},{"do":"dbSetStock","item":"Desk Lamp","quantity":0,"settleMs":0,"warehouse":"West"},{"actor":"admin","do":"fill","testid":"bundle-name-input","text":"Scarce bundle"},{"actor":"admin","do":"fill","testid":"bundle-price-input","text":"75.00"},{"actor":"admin","do":"fill","testid":"bundle-components-input","text":"[{\"item\":\"Keyboard\",\"quantity\":2},{\"item\":\"Desk Lamp\",\"quantity\":1}]"},{"actor":"admin","do":"click","testid":"bundle-save"},{"actor":"admin","contains":"Scarce bundle","do":"expect","testid":"bundle-card","within":10000},{"actor":"a","do":"click","testid":"bundles-link","unlessVisible":"bundle-card"},{"actor":"b","do":"click","testid":"bundles-link","unlessVisible":"bundle-card"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.bundle-integrity","requiresFeatures":["ecommerce.feature.bundle-checkout"],"role":"guarantee","source":"scenarios/progression-bundle-checkout.json"},{"checkGroupId":"bundle-745","feature":{"actors":["admin","buyer"],"criteria":[{"id":"745a","steps":[{"action":"addBundleToCart","actor":"buyer","do":"callAction","input":{"attribute":"data-bundle-input","contains":"Unavailable bundle","testid":"bundle-card"},"namedAction":{"args":[0],"id":"addBundleToCart","params":[{"in":"body","name":"bundleId","wireType":"u64"}],"path":"/api/cart/bundles","reducer":"add_bundle_to_cart"},"settleMs":1000},{"actor":"buyer","do":"expectActionOutcome","outcome":"application-refused"},{"do":"dbExpectStock","equals":2,"item":"Keyboard","warehouse":"East"},{"do":"dbExpectStock","equals":0,"item":"Desk Lamp","warehouse":"East"},{"actor":"buyer","do":"click","testid":"cart-toggle"},{"absent":true,"actor":"buyer","contains":"Unavailable bundle","do":"expect","testid":"cart-item","within":10000}]}],"id":745,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"click","testid":"bundles-link","unlessVisible":"bundle-name-input"},{"actor":"buyer","do":"signUp","name":"bundle-partial"},{"do":"dbSetStock","item":"Keyboard","quantity":2,"settleMs":0,"warehouse":"East"},{"do":"dbSetStock","item":"Keyboard","quantity":0,"settleMs":0,"warehouse":"West"},{"do":"dbSetStock","item":"Desk Lamp","quantity":0,"settleMs":0,"warehouse":"East"},{"do":"dbSetStock","item":"Desk Lamp","quantity":0,"settleMs":0,"warehouse":"West"},{"actor":"admin","do":"fill","testid":"bundle-name-input","text":"Unavailable bundle"},{"actor":"admin","do":"fill","testid":"bundle-price-input","text":"75.00"},{"actor":"admin","do":"fill","testid":"bundle-components-input","text":"[{\"item\":\"Keyboard\",\"quantity\":2},{\"item\":\"Desk Lamp\",\"quantity\":1}]"},{"actor":"admin","do":"click","testid":"bundle-save"},{"actor":"admin","contains":"Unavailable bundle","do":"expect","testid":"bundle-card","within":10000},{"actor":"buyer","do":"click","testid":"bundles-link","unlessVisible":"bundle-card"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.bundle-integrity","requiresFeatures":["ecommerce.feature.bundle-checkout"],"role":"guarantee","source":"scenarios/progression-bundle-checkout.json"},{"checkGroupId":"bundle-746","feature":{"actors":["admin","buyer"],"criteria":[{"id":"746a","steps":[{"actor":"buyer","do":"click","in":{"contains":"Expiring bundle","testid":"bundle-card"},"settleMs":500,"testid":"bundle-add-to-cart"},{"do":"dbExpectStock","equals":4,"item":"Keyboard","warehouse":"East"},{"do":"dbExpectStock","equals":3,"item":"Desk Lamp","warehouse":"East"},{"do":"restartBackend","settleMs":1500},{"actor":"buyer","do":"wait","ms":92000},{"actor":"buyer","do":"reload","settleMs":1000},{"actor":"buyer","do":"ensureSignedIn","name":"bundle-expiry","readyTestid":"current-user"},{"actor":"buyer","do":"click","testid":"cart-toggle"},{"actor":"buyer","do":"expect","in":{"contains":"Expiring bundle","testid":"cart-item"},"testid":"cart-item-expired","within":10000},{"do":"dbExpectStock","equals":6,"item":"Keyboard","warehouse":"East"},{"do":"dbExpectStock","equals":4,"item":"Desk Lamp","warehouse":"East"},{"do":"restartBackend","settleMs":1500},{"do":"dbExpectStock","equals":6,"item":"Keyboard","warehouse":"East"},{"do":"dbExpectStock","equals":4,"item":"Desk Lamp","warehouse":"East"}]}],"id":746,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"click","testid":"bundles-link","unlessVisible":"bundle-name-input"},{"actor":"buyer","do":"signUp","name":"bundle-expiry"},{"do":"dbSetStock","item":"Keyboard","quantity":6,"settleMs":0,"warehouse":"East"},{"do":"dbSetStock","item":"Keyboard","quantity":0,"settleMs":0,"warehouse":"West"},{"do":"dbSetStock","item":"Desk Lamp","quantity":4,"settleMs":0,"warehouse":"East"},{"do":"dbSetStock","item":"Desk Lamp","quantity":0,"settleMs":0,"warehouse":"West"},{"actor":"admin","do":"fill","testid":"bundle-name-input","text":"Expiring bundle"},{"actor":"admin","do":"fill","testid":"bundle-price-input","text":"75.00"},{"actor":"admin","do":"fill","testid":"bundle-components-input","text":"[{\"item\":\"Keyboard\",\"quantity\":2},{\"item\":\"Desk Lamp\",\"quantity\":1}]"},{"actor":"admin","do":"click","testid":"bundle-save"},{"actor":"admin","contains":"Expiring bundle","do":"expect","testid":"bundle-card","within":10000},{"actor":"buyer","do":"click","testid":"bundles-link","unlessVisible":"bundle-card"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.bundle-integrity","requiresFeatures":["ecommerce.feature.bundle-checkout"],"role":"guarantee","source":"scenarios/progression-bundle-checkout.json"},{"checkGroupId":"bundle-747","feature":{"actors":["admin","a","b"],"criteria":[{"id":"747a","steps":[{"action":"checkout","actors":["a","b"],"do":"callConcurrently","settleMs":1000},{"accepted":1,"do":"expectCallOutcomes"},{"actor":"a","do":"reload","settleMs":1000},{"actor":"a","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"a","do":"click","testid":"orders-toggle"},{"actor":"a","contains":"Repeated bundle","count":1,"do":"expect","testid":"order-item","within":10000},{"actor":"a","do":"expectNumber","equals":75,"in":{"contains":"Repeated bundle","testid":"order-item"},"testid":"payment-amount","within":10000},{"do":"dbExpectStock","equals":4,"item":"Keyboard","warehouse":"East"},{"do":"dbExpectStock","equals":3,"item":"Desk Lamp","warehouse":"East"}]}],"id":747,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"click","testid":"bundles-link","unlessVisible":"bundle-name-input"},{"actor":"a","do":"signUp","name":"bundle-repeat"},{"actor":"b","do":"signIn","name":"bundle-repeat"},{"do":"dbSetStock","item":"Keyboard","quantity":6,"settleMs":0,"warehouse":"East"},{"do":"dbSetStock","item":"Keyboard","quantity":0,"settleMs":0,"warehouse":"West"},{"do":"dbSetStock","item":"Desk Lamp","quantity":4,"settleMs":0,"warehouse":"East"},{"do":"dbSetStock","item":"Desk Lamp","quantity":0,"settleMs":0,"warehouse":"West"},{"actor":"admin","do":"fill","testid":"bundle-name-input","text":"Repeated bundle"},{"actor":"admin","do":"fill","testid":"bundle-price-input","text":"75.00"},{"actor":"admin","do":"fill","testid":"bundle-components-input","text":"[{\"item\":\"Keyboard\",\"quantity\":2},{\"item\":\"Desk Lamp\",\"quantity\":1}]"},{"actor":"admin","do":"click","testid":"bundle-save"},{"actor":"admin","contains":"Repeated bundle","do":"expect","testid":"bundle-card","within":10000},{"actor":"a","do":"click","testid":"bundles-link","unlessVisible":"bundle-card"},{"actor":"a","do":"click","in":{"contains":"Repeated bundle","testid":"bundle-card"},"settleMs":500,"testid":"bundle-add-to-cart"},{"do":"dbExpectStock","equals":4,"item":"Keyboard","warehouse":"East"},{"do":"dbExpectStock","equals":3,"item":"Desk Lamp","warehouse":"East"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.bundle-integrity","requiresFeatures":["ecommerce.feature.bundle-checkout"],"role":"guarantee","source":"scenarios/progression-bundle-checkout.json"}],"id":"selected-source-066","scenario":{"level":5,"writeUrlPattern":null},"source":"scenarios/progression-bundle-checkout.json"},{"checkGroups":[{"checkGroupId":"bundle-returns","feature":{"actors":["admin","buyer","staff"],"criteria":[{"id":"742a","steps":[{"actor":"admin","do":"fill","testid":"bundle-name-input","text":"Historical bundle"},{"actor":"admin","do":"fill","testid":"bundle-price-input","text":"9.00"},{"actor":"admin","do":"fill","testid":"bundle-components-input","text":"[{\"item\":\"Keyboard\",\"quantity\":1},{\"item\":\"Desk Lamp\",\"quantity\":3}]"},{"actor":"admin","do":"click","testid":"bundle-save"},{"actor":"admin","contains":"Historical bundle","do":"expect","testid":"bundle-card","within":10000},{"actor":"buyer","do":"click","in":{"contains":"Historical bundle","testid":"order-item"},"testid":"return-bundle"},{"actor":"buyer","do":"expect","ignoreCase":true,"in":{"contains":"Historical bundle","testid":"order-item"},"testid":"order-status","value":"returned","within":10000},{"actor":"buyer","do":"expectNumber","equals":75,"in":{"contains":"Historical bundle","testid":"order-item"},"testid":"bundle-refund-amount","within":10000},{"do":"dbExpectStock","equals":6,"item":"Keyboard","warehouse":"East"},{"do":"dbExpectStock","equals":4,"item":"Desk Lamp","warehouse":"East"},{"do":"dbExpectStock","equals":0,"item":"Keyboard","warehouse":"West"},{"do":"dbExpectStock","equals":0,"item":"Desk Lamp","warehouse":"West"}]}],"id":742,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"click","testid":"bundles-link","unlessVisible":"bundle-name-input"},{"actor":"buyer","do":"signUp","name":"Historical bundle"},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"do":"dbSetStock","item":"Keyboard","quantity":6,"settleMs":0,"warehouse":"East"},{"do":"dbSetStock","item":"Keyboard","quantity":0,"settleMs":0,"warehouse":"West"},{"do":"dbSetStock","item":"Desk Lamp","quantity":4,"settleMs":0,"warehouse":"East"},{"do":"dbSetStock","item":"Desk Lamp","quantity":0,"settleMs":0,"warehouse":"West"},{"actor":"admin","do":"fill","testid":"bundle-name-input","text":"Historical bundle"},{"actor":"admin","do":"fill","testid":"bundle-price-input","text":"75.00"},{"actor":"admin","do":"fill","testid":"bundle-components-input","text":"[{\"item\":\"Keyboard\",\"quantity\":2},{\"item\":\"Desk Lamp\",\"quantity\":1}]"},{"actor":"admin","do":"click","testid":"bundle-save"},{"actor":"admin","contains":"Historical bundle","do":"expect","testid":"bundle-card","within":10000},{"actor":"buyer","do":"click","testid":"bundles-link","unlessVisible":"bundle-card"},{"actor":"buyer","do":"click","in":{"contains":"Historical bundle","testid":"bundle-card"},"testid":"bundle-add-to-cart"},{"actor":"buyer","do":"click","testid":"cart-toggle"},{"actor":"buyer","do":"click","testid":"checkout-submit"},{"actor":"buyer","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"buyer","do":"click","testid":"orders-toggle"},{"actor":"buyer","contains":"Historical bundle","count":1,"do":"expect","testid":"order-item","within":10000},{"actor":"buyer","do":"expectNumber","equals":75,"in":{"contains":"Historical bundle","testid":"order-item"},"testid":"payment-amount","within":10000},{"do":"dbExpectStock","equals":4,"item":"Keyboard","warehouse":"East"},{"do":"dbExpectStock","equals":3,"item":"Desk Lamp","warehouse":"East"},{"actor":"staff","do":"click","testid":"staff-link"},{"actor":"staff","contains":"Historical bundle","do":"expect","testid":"queue-item","within":10000},{"actor":"staff","do":"click","in":{"contains":"Historical bundle","testid":"queue-item"},"testid":"ship-submit"},{"actor":"buyer","do":"expect","ignoreCase":true,"in":{"contains":"Historical bundle","testid":"order-item"},"testid":"order-status","value":"shipped","within":10000}]},"packId":"ecommerce.feature.bundle-returns","role":"feature","source":"scenarios/progression-bundle-returns.json"},{"checkGroupId":"bundle-742","feature":{"actors":["admin","buyer","staff"],"criteria":[{"id":"742b","steps":[{"do":"restartBackend","settleMs":1500},{"actor":"buyer","do":"reload","settleMs":1000},{"actor":"buyer","do":"ensureSignedIn","name":"Historical bundle","readyTestid":"current-user"},{"actor":"buyer","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"buyer","do":"click","testid":"orders-toggle"},{"action":"returnBundle","actor":"buyer","do":"callAction","input":{"attribute":"data-bundle-return-input","contains":"Historical bundle","testid":"order-item"},"namedAction":{"args":[0],"id":"returnBundle","params":[{"in":"path","name":"orderId","placeholder":":orderId","wireType":"u64"}],"path":"/api/bundle-orders/:orderId/return","reducer":"return_bundle"},"settleMs":1000},{"actor":"buyer","do":"reload","settleMs":1000},{"actor":"buyer","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"buyer","do":"click","testid":"orders-toggle"},{"actor":"buyer","do":"expectNumber","equals":75,"in":{"contains":"Historical bundle","testid":"order-item"},"testid":"bundle-refund-amount","within":10000},{"do":"dbExpectStock","equals":6,"item":"Keyboard","warehouse":"East"},{"do":"dbExpectStock","equals":4,"item":"Desk Lamp","warehouse":"East"}]}],"id":742,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"click","testid":"bundles-link","unlessVisible":"bundle-name-input"},{"actor":"buyer","do":"signUp","name":"Historical bundle"},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"do":"dbSetStock","item":"Keyboard","quantity":6,"settleMs":0,"warehouse":"East"},{"do":"dbSetStock","item":"Keyboard","quantity":0,"settleMs":0,"warehouse":"West"},{"do":"dbSetStock","item":"Desk Lamp","quantity":4,"settleMs":0,"warehouse":"East"},{"do":"dbSetStock","item":"Desk Lamp","quantity":0,"settleMs":0,"warehouse":"West"},{"actor":"admin","do":"fill","testid":"bundle-name-input","text":"Historical bundle"},{"actor":"admin","do":"fill","testid":"bundle-price-input","text":"75.00"},{"actor":"admin","do":"fill","testid":"bundle-components-input","text":"[{\"item\":\"Keyboard\",\"quantity\":2},{\"item\":\"Desk Lamp\",\"quantity\":1}]"},{"actor":"admin","do":"click","testid":"bundle-save"},{"actor":"admin","contains":"Historical bundle","do":"expect","testid":"bundle-card","within":10000},{"actor":"buyer","do":"click","testid":"bundles-link","unlessVisible":"bundle-card"},{"actor":"buyer","do":"click","in":{"contains":"Historical bundle","testid":"bundle-card"},"testid":"bundle-add-to-cart"},{"actor":"buyer","do":"click","testid":"cart-toggle"},{"actor":"buyer","do":"click","testid":"checkout-submit"},{"actor":"buyer","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"buyer","do":"click","testid":"orders-toggle"},{"actor":"buyer","contains":"Historical bundle","count":1,"do":"expect","testid":"order-item","within":10000},{"actor":"buyer","do":"expectNumber","equals":75,"in":{"contains":"Historical bundle","testid":"order-item"},"testid":"payment-amount","within":10000},{"do":"dbExpectStock","equals":4,"item":"Keyboard","warehouse":"East"},{"do":"dbExpectStock","equals":3,"item":"Desk Lamp","warehouse":"East"},{"actor":"staff","do":"click","testid":"staff-link"},{"actor":"staff","contains":"Historical bundle","do":"expect","testid":"queue-item","within":10000},{"actor":"staff","do":"click","in":{"contains":"Historical bundle","testid":"queue-item"},"testid":"ship-submit"},{"actor":"buyer","do":"expect","ignoreCase":true,"in":{"contains":"Historical bundle","testid":"order-item"},"testid":"order-status","value":"shipped","within":10000}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.bundle-integrity","requiresFeatures":["ecommerce.feature.bundle-returns"],"role":"guarantee","source":"scenarios/progression-bundle-returns.json"},{"checkGroupId":"bundle-748","feature":{"actors":["admin","buyer","staff","other"],"criteria":[{"id":"748a","steps":[{"action":"returnBundle","actor":"other","do":"callAction","from":"buyer","input":{"attribute":"data-bundle-return-input","contains":"Private bundle","testid":"order-item"},"namedAction":{"args":[0],"id":"returnBundle","params":[{"in":"path","name":"orderId","placeholder":":orderId","wireType":"u64"}],"path":"/api/bundle-orders/:orderId/return","reducer":"return_bundle"},"settleMs":1000},{"actor":"other","do":"expectActionOutcome","outcome":"application-refused"},{"actor":"buyer","do":"reload","settleMs":1000},{"actor":"buyer","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"buyer","do":"click","testid":"orders-toggle"},{"actor":"buyer","do":"expect","ignoreCase":true,"in":{"contains":"Private bundle","testid":"order-item"},"testid":"order-status","value":"shipped","within":10000},{"do":"dbExpectStock","equals":4,"item":"Keyboard","warehouse":"East"},{"do":"dbExpectStock","equals":3,"item":"Desk Lamp","warehouse":"East"},{"actor":"buyer","do":"click","in":{"contains":"Private bundle","testid":"order-item"},"testid":"return-bundle"},{"actor":"buyer","do":"expectNumber","equals":75,"in":{"contains":"Private bundle","testid":"order-item"},"testid":"bundle-refund-amount","within":10000},{"do":"dbExpectStock","equals":6,"item":"Keyboard","warehouse":"East"},{"do":"dbExpectStock","equals":4,"item":"Desk Lamp","warehouse":"East"}]}],"id":748,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"click","testid":"bundles-link","unlessVisible":"bundle-name-input"},{"actor":"buyer","do":"signUp","name":"Private bundle"},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"do":"dbSetStock","item":"Keyboard","quantity":6,"settleMs":0,"warehouse":"East"},{"do":"dbSetStock","item":"Keyboard","quantity":0,"settleMs":0,"warehouse":"West"},{"do":"dbSetStock","item":"Desk Lamp","quantity":4,"settleMs":0,"warehouse":"East"},{"do":"dbSetStock","item":"Desk Lamp","quantity":0,"settleMs":0,"warehouse":"West"},{"actor":"admin","do":"fill","testid":"bundle-name-input","text":"Private bundle"},{"actor":"admin","do":"fill","testid":"bundle-price-input","text":"75.00"},{"actor":"admin","do":"fill","testid":"bundle-components-input","text":"[{\"item\":\"Keyboard\",\"quantity\":2},{\"item\":\"Desk Lamp\",\"quantity\":1}]"},{"actor":"admin","do":"click","testid":"bundle-save"},{"actor":"admin","contains":"Private bundle","do":"expect","testid":"bundle-card","within":10000},{"actor":"buyer","do":"click","testid":"bundles-link","unlessVisible":"bundle-card"},{"actor":"buyer","do":"click","in":{"contains":"Private bundle","testid":"bundle-card"},"testid":"bundle-add-to-cart"},{"actor":"buyer","do":"click","testid":"cart-toggle"},{"actor":"buyer","do":"click","testid":"checkout-submit"},{"actor":"buyer","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"buyer","do":"click","testid":"orders-toggle"},{"actor":"buyer","contains":"Private bundle","count":1,"do":"expect","testid":"order-item","within":10000},{"actor":"buyer","do":"expectNumber","equals":75,"in":{"contains":"Private bundle","testid":"order-item"},"testid":"payment-amount","within":10000},{"do":"dbExpectStock","equals":4,"item":"Keyboard","warehouse":"East"},{"do":"dbExpectStock","equals":3,"item":"Desk Lamp","warehouse":"East"},{"actor":"staff","do":"click","testid":"staff-link"},{"actor":"staff","contains":"Private bundle","do":"expect","testid":"queue-item","within":10000},{"actor":"staff","do":"click","in":{"contains":"Private bundle","testid":"queue-item"},"testid":"ship-submit"},{"actor":"buyer","do":"expect","ignoreCase":true,"in":{"contains":"Private bundle","testid":"order-item"},"testid":"order-status","value":"shipped","within":10000},{"actor":"other","do":"signUp","name":"bundle-other"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.bundle-integrity","requiresFeatures":["ecommerce.feature.bundle-returns"],"role":"guarantee","source":"scenarios/progression-bundle-returns.json"}],"id":"selected-source-067","scenario":{"level":6,"writeUrlPattern":null},"source":"scenarios/progression-bundle-returns.json"},{"checkGroups":[{"checkGroupId":"cart","feature":{"actors":["quantity","checkout"],"criteria":[{"id":"4a","steps":[{"actor":"quantity","do":"click","in":{"contains":"Headphones","testid":"item-card"},"testid":"add-to-cart"},{"actor":"quantity","do":"wait","ms":800},{"actor":"quantity","do":"click","ifAvailable":true,"testid":"overlay-close"},{"actor":"quantity","do":"click","ifAvailable":true,"testid":"catalog-link"},{"actor":"quantity","do":"click","in":{"contains":"Headphones","testid":"item-card"},"testid":"add-to-cart"},{"actor":"quantity","do":"click","testid":"cart-toggle","unlessVisible":"cart-total"},{"actor":"quantity","contains":"Headphones","count":1,"do":"expect","testid":"cart-item"},{"actor":"quantity","do":"expectNumber","equals":2,"in":{"contains":"Headphones","testid":"cart-item"},"testid":"cart-quantity"}]}],"id":4,"setup":[{"actor":"quantity","do":"signUp","name":"cart-quantity"},{"actor":"checkout","do":"signUp","name":"cart-checkout"}]},"packId":"ecommerce.feature.cart","role":"feature","source":"scenarios/progression-cart-checkout.json","stablePackId":"ecommerce.feature.cart-checkout"},{"checkGroupId":"cart","feature":{"actors":["quantity","checkout"],"criteria":[{"id":"4d","steps":[{"actor":"checkout","do":"expectNumber","equals":100,"in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"item-stock"},{"actor":"checkout","do":"click","in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"add-to-cart"},{"actor":"checkout","do":"click","testid":"cart-toggle","unlessVisible":"cart-total"},{"actor":"checkout","do":"expectNumber","equals":1,"testid":"cart-count"},{"actor":"checkout","do":"click","testid":"checkout-submit"},{"actor":"checkout","do":"wait","ms":1500},{"actor":"checkout","do":"reload","settleMs":2500},{"actor":"checkout","do":"ensureSignedIn","name":"cart-checkout","readyTestid":"current-user"},{"actor":"checkout","do":"click","testid":"cart-toggle","unlessVisible":"cart-total"},{"actor":"checkout","do":"expectNumber","equals":0,"testid":"cart-count"},{"actor":"checkout","do":"click","ifAvailable":true,"testid":"overlay-close"},{"actor":"checkout","do":"click","ifAvailable":true,"testid":"catalog-link"},{"actor":"checkout","do":"expectNumber","equals":99,"in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"item-stock"},{"actor":"checkout","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"checkout","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"checkout","contains":"Desk Lamp","count":1,"do":"expect","testid":"order-item"}]}],"id":4,"setup":[{"actor":"quantity","do":"signUp","name":"cart-quantity"},{"actor":"checkout","do":"signUp","name":"cart-checkout"}]},"packId":"ecommerce.feature.checkout","role":"feature","source":"scenarios/progression-cart-checkout.json","stablePackId":"ecommerce.feature.cart-checkout"}],"id":"selected-source-068","scenario":{"level":1,"writeUrlPattern":null},"source":"scenarios/progression-cart-checkout.json"},{"checkGroups":[{"checkGroupId":"cart-recovery","feature":{"actors":["available-shopper","partial-shopper"],"criteria":[{"id":"503a","steps":[{"actor":"available-shopper","do":"reload","settleMs":1000},{"actor":"available-shopper","do":"ensureSignedIn","name":"cart-recovery-available","readyTestid":"current-user"},{"actor":"available-shopper","do":"expect","testid":"expired-cart"},{"actor":"available-shopper","do":"expectNumber","equals":0,"testid":"cart-count"},{"actor":"available-shopper","as":"restore-available-shopper","do":"recordNumber","in":{"contains":"Keyboard","testid":"item-card"},"testid":"item-stock"},{"actor":"available-shopper","do":"click","in":{"testid":"expired-cart"},"testid":"restore-cart"},{"actor":"available-shopper","do":"click","testid":"cart-toggle"},{"actor":"available-shopper","contains":"Keyboard","do":"expect","testid":"cart-item"},{"absent":true,"actor":"available-shopper","do":"expect","testid":"cart-restore-warning"},{"actor":"available-shopper","do":"expectNumber","equals":1,"in":{"contains":"Keyboard","testid":"cart-item"},"testid":"cart-quantity"},{"actor":"available-shopper","do":"reload","settleMs":1000},{"actor":"available-shopper","do":"ensureSignedIn","name":"cart-recovery-available","readyTestid":"current-user"},{"actor":"available-shopper","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"available-shopper","do":"click","testid":"catalog-link","unlessVisible":"item-card"},{"actor":"available-shopper","do":"expectNumber","in":{"contains":"Keyboard","testid":"item-card"},"plus":-1,"relativeTo":"restore-available-shopper","testid":"item-stock"}]}],"id":503,"setup":[{"actor":"available-shopper","do":"signUp","name":"cart-recovery-available"},{"actor":"available-shopper","do":"click","in":{"contains":"Keyboard","testid":"item-card"},"testid":"add-to-cart"},{"actor":"partial-shopper","do":"signUp","name":"cart-recovery-partial"},{"actor":"partial-shopper","do":"click","in":{"contains":"Gaming Mouse","testid":"item-card"},"testid":"add-to-cart"},{"actor":"partial-shopper","do":"click","in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"add-to-cart"},{"actor":"available-shopper","do":"wait","ms":310000}]},"packId":"ecommerce.progression.cart-recovery","role":"feature","source":"scenarios/progression-cart-recovery.json"},{"checkGroupId":"cart-recovery","feature":{"actors":["available-shopper","partial-shopper"],"criteria":[{"id":"503b","steps":[{"actor":"partial-shopper","do":"reload","settleMs":1000},{"actor":"partial-shopper","do":"ensureSignedIn","name":"cart-recovery-partial","readyTestid":"current-user"},{"actor":"partial-shopper","do":"expect","testid":"expired-cart"},{"actor":"partial-shopper","do":"expectNumber","equals":0,"testid":"cart-count"},{"actor":"partial-shopper","as":"restore-partial-shopper","do":"recordNumber","in":{"contains":"Gaming Mouse","testid":"item-card"},"testid":"item-stock"},{"do":"dbSetStock","item":"Desk Lamp","quantity":0,"settleMs":2000,"warehouse":"East"},{"do":"dbSetStock","item":"Desk Lamp","quantity":0,"settleMs":2000,"warehouse":"West"},{"actor":"partial-shopper","do":"click","in":{"testid":"expired-cart"},"testid":"restore-cart"},{"actor":"partial-shopper","do":"click","testid":"cart-toggle"},{"actor":"partial-shopper","contains":"Gaming Mouse","do":"expect","testid":"cart-item"},{"absent":true,"actor":"partial-shopper","contains":"Desk Lamp","do":"expect","testid":"cart-item"},{"actor":"partial-shopper","contains":"Desk Lamp","do":"expect","testid":"cart-restore-warning"},{"actor":"partial-shopper","do":"expectNumber","equals":1,"in":{"contains":"Gaming Mouse","testid":"cart-item"},"testid":"cart-quantity"},{"actor":"partial-shopper","do":"reload","settleMs":1000},{"actor":"partial-shopper","do":"ensureSignedIn","name":"cart-recovery-partial","readyTestid":"current-user"},{"actor":"partial-shopper","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"partial-shopper","do":"click","testid":"catalog-link","unlessVisible":"item-card"},{"actor":"partial-shopper","do":"expectNumber","in":{"contains":"Gaming Mouse","testid":"item-card"},"plus":-1,"relativeTo":"restore-partial-shopper","testid":"item-stock"}]}],"id":503,"setup":[{"actor":"available-shopper","do":"signUp","name":"cart-recovery-available"},{"actor":"available-shopper","do":"click","in":{"contains":"Keyboard","testid":"item-card"},"testid":"add-to-cart"},{"actor":"partial-shopper","do":"signUp","name":"cart-recovery-partial"},{"actor":"partial-shopper","do":"click","in":{"contains":"Gaming Mouse","testid":"item-card"},"testid":"add-to-cart"},{"actor":"partial-shopper","do":"click","in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"add-to-cart"},{"actor":"available-shopper","do":"wait","ms":310000}]},"packId":"ecommerce.progression.cart-recovery","role":"feature","source":"scenarios/progression-cart-recovery.json"}],"id":"selected-source-069","scenario":{"level":5,"writeUrlPattern":null},"source":"scenarios/progression-cart-recovery.json"},{"checkGroups":[{"checkGroupId":"catalog-management","feature":{"actors":["admin","visitor"],"criteria":[{"id":"622a","steps":[{"actor":"visitor","contains":"Travel Mug","do":"expect","testid":"item-card","within":10000}]},{"id":"622b","steps":[{"actor":"visitor","do":"openItem","item":"Travel Mug","unlessVisible":"item-variant"},{"actor":"visitor","contains":"Black","do":"expectElementCount","equals":1,"testid":"item-variant","within":10000},{"actor":"visitor","contains":"Silver","do":"expectElementCount","equals":1,"testid":"item-variant","within":10000}]}],"id":622,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"click","testid":"admin-link"},{"actor":"admin","do":"fill","testid":"catalog-name","text":"Travel Mug"},{"actor":"admin","do":"fill","testid":"catalog-category","text":"Kitchen"},{"actor":"admin","do":"fill","testid":"catalog-price","text":"24.00"},{"actor":"admin","do":"fill","testid":"catalog-variants","text":"Black, Silver"},{"actor":"admin","do":"click","testid":"catalog-save"},{"actor":"visitor","do":"reload","settleMs":2500},{"actor":"visitor","do":"fill","enter":true,"testid":"search-input","text":"Travel Mug"}]},"packId":"ecommerce.progression.catalog-management","role":"feature","source":"scenarios/progression-catalog-management.json"}],"id":"selected-source-070","scenario":{"level":5,"writeUrlPattern":null},"source":"scenarios/progression-catalog-management.json"},{"checkGroups":[{"checkGroupId":"checkout-crash-integrity","feature":{"actors":["a","b","c"],"criteria":[{"id":"910a","steps":[{"do":"expectCrashCheckout","from":"database-crash-observation","verdict":"atomicity"},{"do":"expectCrashCheckout","from":"application-crash-observation","verdict":"atomicity"}]}],"id":910,"setup":[{"actor":"a","do":"signUp","name":"database"},{"account":"{user:database}","as":"database-baseline-before","do":"dbRecordCheckout","item":"Keyboard","storage":{"cart":true,"kind":"order-data","warehouses":false}},{"actor":"a","do":"click","in":{"contains":"Keyboard","testid":"item-card"},"testid":"add-to-cart"},{"account":"{user:database}","as":"database-baseline-prepared","do":"dbRecordCheckout","item":"Keyboard","storage":{"cart":true,"kind":"order-data","warehouses":false}},{"actor":"a","do":"confirmCheckout","namedAction":{"args":[],"id":"checkout","path":"/api/checkout","reducer":"checkout"}},{"before":"database-baseline-before","do":"dbExpectCheckout","prepared":"database-baseline-prepared","quantity":1},{"actor":"a","do":"reload","settleMs":0},{"account":"{user:database}","as":"database-before","do":"dbRecordCheckout","item":"Keyboard","storage":{"cart":true,"kind":"order-data","warehouses":false}},{"actor":"a","do":"click","in":{"contains":"Keyboard","testid":"item-card"},"testid":"add-to-cart"},{"account":"{user:database}","as":"database-prepared","do":"dbRecordCheckout","item":"Keyboard","storage":{"cart":true,"kind":"order-data","warehouses":false}},{"actor":"a","as":"database-crash-observation","before":"database-before","do":"crashCheckout","namedAction":{"args":[],"id":"checkout","path":"/api/checkout","reducer":"checkout"},"offsetMs":0,"prepared":"database-prepared","quantity":1,"requests":16,"target":"database"},{"actor":"b","do":"signUp","name":"application"},{"account":"{user:application}","as":"application-baseline-before","do":"dbRecordCheckout","item":"Keyboard","storage":{"cart":true,"kind":"order-data","warehouses":false}},{"actor":"b","do":"click","in":{"contains":"Keyboard","testid":"item-card"},"testid":"add-to-cart"},{"account":"{user:application}","as":"application-baseline-prepared","do":"dbRecordCheckout","item":"Keyboard","storage":{"cart":true,"kind":"order-data","warehouses":false}},{"actor":"b","do":"confirmCheckout","namedAction":{"args":[],"id":"checkout","path":"/api/checkout","reducer":"checkout"}},{"before":"application-baseline-before","do":"dbExpectCheckout","prepared":"application-baseline-prepared","quantity":1},{"actor":"b","do":"reload","settleMs":0},{"account":"{user:application}","as":"application-before","do":"dbRecordCheckout","item":"Keyboard","storage":{"cart":true,"kind":"order-data","warehouses":false}},{"actor":"b","do":"click","in":{"contains":"Keyboard","testid":"item-card"},"testid":"add-to-cart"},{"account":"{user:application}","as":"application-prepared","do":"dbRecordCheckout","item":"Keyboard","storage":{"cart":true,"kind":"order-data","warehouses":false}},{"actor":"b","as":"application-crash-observation","before":"application-before","do":"crashCheckout","namedAction":{"args":[],"id":"checkout","path":"/api/checkout","reducer":"checkout"},"offsetMs":0,"prepared":"application-prepared","quantity":1,"requests":16,"reuseCombinedFrom":"database-crash-observation","target":"application"},{"actor":"c","do":"signUp","name":"recovered"},{"account":"{user:recovered}","as":"recovered-before","do":"dbRecordCheckout","item":"Keyboard","storage":{"cart":true,"kind":"order-data","warehouses":false}},{"actor":"c","do":"click","in":{"contains":"Keyboard","testid":"item-card"},"testid":"add-to-cart"},{"account":"{user:recovered}","as":"recovered-prepared","do":"dbRecordCheckout","item":"Keyboard","storage":{"cart":true,"kind":"order-data","warehouses":false}},{"actor":"c","do":"click","testid":"cart-toggle"},{"actor":"c","do":"click","testid":"checkout-submit"},{"actor":"c","do":"expectNumber","equals":0,"testid":"cart-count","within":10000},{"actor":"c","do":"click","ifAvailable":true,"testid":"overlay-close"},{"before":"recovered-before","do":"dbExpectCheckout","prepared":"recovered-prepared","quantity":1}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.state-durability","requiresFeatures":["ecommerce.feature.checkout"],"role":"guarantee","source":"scenarios/progression-checkout-crash.json"},{"checkGroupId":"checkout-crash-durability","feature":{"actors":["a","b","c"],"criteria":[{"id":"910b","steps":[{"do":"expectCrashCheckout","from":"database-crash-observation","verdict":"durability"},{"do":"expectCrashCheckout","from":"application-crash-observation","verdict":"durability"}]}],"id":910,"setup":[{"actor":"a","do":"signUp","name":"database"},{"account":"{user:database}","as":"database-baseline-before","do":"dbRecordCheckout","item":"Keyboard","storage":{"cart":true,"kind":"order-data","warehouses":false}},{"actor":"a","do":"click","in":{"contains":"Keyboard","testid":"item-card"},"testid":"add-to-cart"},{"account":"{user:database}","as":"database-baseline-prepared","do":"dbRecordCheckout","item":"Keyboard","storage":{"cart":true,"kind":"order-data","warehouses":false}},{"actor":"a","do":"confirmCheckout","namedAction":{"args":[],"id":"checkout","path":"/api/checkout","reducer":"checkout"}},{"before":"database-baseline-before","do":"dbExpectCheckout","prepared":"database-baseline-prepared","quantity":1},{"actor":"a","do":"reload","settleMs":0},{"account":"{user:database}","as":"database-before","do":"dbRecordCheckout","item":"Keyboard","storage":{"cart":true,"kind":"order-data","warehouses":false}},{"actor":"a","do":"click","in":{"contains":"Keyboard","testid":"item-card"},"testid":"add-to-cart"},{"account":"{user:database}","as":"database-prepared","do":"dbRecordCheckout","item":"Keyboard","storage":{"cart":true,"kind":"order-data","warehouses":false}},{"actor":"a","as":"database-crash-observation","before":"database-before","do":"crashCheckout","namedAction":{"args":[],"id":"checkout","path":"/api/checkout","reducer":"checkout"},"offsetMs":0,"prepared":"database-prepared","quantity":1,"requests":16,"target":"database"},{"actor":"b","do":"signUp","name":"application"},{"account":"{user:application}","as":"application-baseline-before","do":"dbRecordCheckout","item":"Keyboard","storage":{"cart":true,"kind":"order-data","warehouses":false}},{"actor":"b","do":"click","in":{"contains":"Keyboard","testid":"item-card"},"testid":"add-to-cart"},{"account":"{user:application}","as":"application-baseline-prepared","do":"dbRecordCheckout","item":"Keyboard","storage":{"cart":true,"kind":"order-data","warehouses":false}},{"actor":"b","do":"confirmCheckout","namedAction":{"args":[],"id":"checkout","path":"/api/checkout","reducer":"checkout"}},{"before":"application-baseline-before","do":"dbExpectCheckout","prepared":"application-baseline-prepared","quantity":1},{"actor":"b","do":"reload","settleMs":0},{"account":"{user:application}","as":"application-before","do":"dbRecordCheckout","item":"Keyboard","storage":{"cart":true,"kind":"order-data","warehouses":false}},{"actor":"b","do":"click","in":{"contains":"Keyboard","testid":"item-card"},"testid":"add-to-cart"},{"account":"{user:application}","as":"application-prepared","do":"dbRecordCheckout","item":"Keyboard","storage":{"cart":true,"kind":"order-data","warehouses":false}},{"actor":"b","as":"application-crash-observation","before":"application-before","do":"crashCheckout","namedAction":{"args":[],"id":"checkout","path":"/api/checkout","reducer":"checkout"},"offsetMs":0,"prepared":"application-prepared","quantity":1,"requests":16,"reuseCombinedFrom":"database-crash-observation","target":"application"},{"actor":"c","do":"signUp","name":"recovered"},{"account":"{user:recovered}","as":"recovered-before","do":"dbRecordCheckout","item":"Keyboard","storage":{"cart":true,"kind":"order-data","warehouses":false}},{"actor":"c","do":"click","in":{"contains":"Keyboard","testid":"item-card"},"testid":"add-to-cart"},{"account":"{user:recovered}","as":"recovered-prepared","do":"dbRecordCheckout","item":"Keyboard","storage":{"cart":true,"kind":"order-data","warehouses":false}},{"actor":"c","do":"click","testid":"cart-toggle"},{"actor":"c","do":"click","testid":"checkout-submit"},{"actor":"c","do":"expectNumber","equals":0,"testid":"cart-count","within":10000},{"actor":"c","do":"click","ifAvailable":true,"testid":"overlay-close"},{"before":"recovered-before","do":"dbExpectCheckout","prepared":"recovered-prepared","quantity":1}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.state-durability","requiresFeatures":["ecommerce.feature.checkout"],"role":"guarantee","source":"scenarios/progression-checkout-crash.json"}],"id":"selected-source-071","scenario":{"level":1,"writeUrlPattern":null},"source":"scenarios/progression-checkout-crash.json"},{"checkGroups":[{"checkGroupId":"payment-records","feature":{"actors":["tab1","tab2","owner"],"criteria":[{"id":"623a","steps":[{"actor":"owner-fresh","do":"expect","ignoreCase":true,"in":{"contains":"Desk Lamp","testid":"order-item"},"testid":"payment-status","value":"paid","within":10000},{"actor":"owner-fresh","do":"expectNumber","in":{"contains":"Desk Lamp","testid":"order-item"},"plus":0,"relativeTo":"payment-total","testid":"payment-amount"}]}],"id":623,"setup":[{"actor":"tab1","do":"signUp","name":"payment-record"},{"actor":"tab2","do":"signIn","name":"payment-record"},{"actor":"owner","do":"signIn","name":"payment-record"},{"actor":"owner","do":"click","in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"add-to-cart"},{"actor":"owner","do":"click","testid":"cart-toggle"},{"actor":"owner","as":"payment-total","do":"recordNumber","testid":"cart-total"},{"action":"checkout","actors":["tab1","tab2"],"do":"callConcurrently","settleMs":5000},{"do":"expectCallOutcomes"},{"actor":"owner","do":"freshClient"},{"actor":"owner-fresh","do":"signIn","name":"payment-record"},{"actor":"owner-fresh","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"owner-fresh","do":"click","testid":"orders-toggle"},{"actor":"owner-fresh","contains":"Desk Lamp","do":"expectElementCount","equals":1,"testid":"order-item","within":10000}]},"packId":"ecommerce.progression.payment-records","role":"feature","source":"scenarios/progression-core-business.json"},{"checkGroupId":"payment-deduplication","feature":{"actors":["tab1","tab2","owner"],"criteria":[{"id":"623b","steps":[{"actor":"owner-fresh","do":"expectElementCount","equals":1,"in":{"contains":"Desk Lamp","testid":"order-item"},"testid":"payment-record","within":10000}]}],"id":623,"setup":[{"actor":"tab1","do":"signUp","name":"payment-record"},{"actor":"tab2","do":"signIn","name":"payment-record"},{"actor":"owner","do":"signIn","name":"payment-record"},{"actor":"owner","do":"click","in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"add-to-cart"},{"actor":"owner","do":"click","testid":"cart-toggle"},{"actor":"owner","as":"payment-total","do":"recordNumber","testid":"cart-total"},{"action":"checkout","actors":["tab1","tab2"],"do":"callConcurrently","settleMs":5000},{"do":"expectCallOutcomes"},{"actor":"owner","do":"freshClient"},{"actor":"owner-fresh","do":"signIn","name":"payment-record"},{"actor":"owner-fresh","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"owner-fresh","do":"click","testid":"orders-toggle"},{"actor":"owner-fresh","contains":"Desk Lamp","do":"expectElementCount","equals":1,"testid":"order-item","within":10000}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.transactional-integrity","requiresFeatures":["ecommerce.progression.payment-records"],"role":"guarantee","source":"scenarios/progression-core-business.json"}],"id":"selected-source-072","scenario":{"level":5,"writeUrlPattern":null},"source":"scenarios/progression-core-business.json"},{"checkGroups":[{"checkGroupId":"customer-profile","feature":{"actors":["owner","privateOwner","other"],"criteria":[{"id":"620c","steps":[{"actor":"owner","do":"click","ifAvailable":true,"testid":"overlay-close"},{"actor":"owner","do":"click","ifAvailable":true,"testid":"catalog-link"},{"actor":"owner","do":"click","testid":"profile-link","unlessVisible":"profile-address-summary"},{"actor":"owner","contains":"14 Market Street {user:profilemarker}","do":"expect","testid":"profile-address-summary"}]}],"id":620,"setup":[{"actor":"owner","do":"signUp","name":"profile-owner"},{"actor":"owner","do":"click","testid":"profile-link"},{"actor":"owner","do":"fill","testid":"profile-name","text":"Avery Stone"},{"actor":"owner","do":"fill","testid":"profile-address","text":"14 Market Street {user:profilemarker}"},{"actor":"owner","do":"click","testid":"profile-save"}]},"packId":"ecommerce.progression.customer-profile","role":"feature","source":"scenarios/progression-customer-profile.json"},{"checkGroupId":"customer-profile-reload","feature":{"actors":["owner","privateOwner","other"],"criteria":[{"id":"620a","steps":[{"actor":"owner","do":"reload","settleMs":2500},{"actor":"owner","do":"ensureSignedIn","name":"profile-owner","readyTestid":"current-user"},{"actor":"owner","do":"click","testid":"profile-link"},{"actor":"owner","contains":"14 Market Street {user:profilemarker}","do":"expect","testid":"profile-address-summary"},{"do":"restartBackend","settleMs":1000},{"actor":"owner","do":"freshClient"},{"actor":"owner-fresh","do":"signIn","name":"profile-owner"},{"actor":"owner-fresh","do":"click","testid":"profile-link"},{"actor":"owner-fresh","contains":"14 Market Street {user:profilemarker}","do":"expect","testid":"profile-address-summary"}]}],"id":620,"setup":[{"actor":"owner","do":"signUp","name":"profile-owner"},{"actor":"owner","do":"click","testid":"profile-link"},{"actor":"owner","do":"fill","testid":"profile-name","text":"Avery Stone"},{"actor":"owner","do":"fill","testid":"profile-address","text":"14 Market Street {user:profilemarker}"},{"actor":"owner","do":"click","testid":"profile-save"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.state-durability","requiresFeatures":["ecommerce.progression.customer-profile"],"role":"guarantee","source":"scenarios/progression-customer-profile.json"},{"checkGroupId":"customer-profile-privacy","feature":{"actors":["owner","privateOwner","other"],"criteria":[{"id":"620b","steps":[{"actor":"privateOwner","do":"reload","settleMs":0},{"actor":"privateOwner","do":"signUp","name":"profile-private-owner"},{"actor":"privateOwner","do":"click","testid":"profile-link"},{"actor":"privateOwner","do":"fill","testid":"profile-name","text":"Avery Stone"},{"actor":"privateOwner","do":"fill","testid":"profile-address","text":"14 Market Street {user:profilemarker}"},{"actor":"privateOwner","do":"click","testid":"profile-save"},{"actor":"privateOwner","do":"reload","settleMs":1000},{"actor":"privateOwner","do":"ensureSignedIn","name":"profile-private-owner","readyTestid":"current-user"},{"actor":"privateOwner","do":"click","testid":"profile-link"},{"actor":"privateOwner","contains":"14 Market Street {user:profilemarker}","do":"expect","testid":"profile-address-summary"},{"actor":"privateOwner","contains":"14 Market Street {user:profilemarker}","do":"expectReceived","within":10000},{"actor":"other","do":"reload","settleMs":0},{"actor":"other","do":"signUp","name":"profile-other"},{"actor":"other","do":"click","testid":"profile-link"},{"absent":true,"actor":"other","contains":"14 Market Street {user:profilemarker}","do":"expect","testid":"profile-address-summary"},{"actor":"other","contains":"14 Market Street {user:profilemarker}","do":"expectNotReceived"}]}],"id":620,"setup":[{"actor":"owner","do":"signUp","name":"profile-owner"},{"actor":"owner","do":"click","testid":"profile-link"},{"actor":"owner","do":"fill","testid":"profile-name","text":"Avery Stone"},{"actor":"owner","do":"fill","testid":"profile-address","text":"14 Market Street {user:profilemarker}"},{"actor":"owner","do":"click","testid":"profile-save"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","requiresFeatures":["ecommerce.progression.customer-profile"],"role":"guarantee","source":"scenarios/progression-customer-profile.json"}],"id":"selected-source-073","scenario":{"level":2,"writeUrlPattern":null},"source":"scenarios/progression-customer-profile.json"},{"checkGroups":[{"checkGroupId":"delivery-notification-delivery","feature":{"actors":["owner","other","staff"],"criteria":[{"id":"501a","steps":[{"actor":"owner","do":"reload","settleMs":1000},{"actor":"owner","do":"ensureSignedIn","name":"delivery-owner","readyTestid":"current-user"},{"actor":"owner","do":"click","testid":"notifications-toggle","unlessVisible":"notifications-panel"},{"actor":"owner","attribute":"aria-busy","do":"expect","testid":"notifications-panel","value":"false","within":10000},{"actor":"owner","contains":"Desk Lamp","do":"expectElementCount","equals":1,"testid":"notification-item","within":10000}]}],"id":501,"setup":[{"actor":"owner","do":"signUp","name":"delivery-owner"},{"actor":"other","do":"signUp","name":"delivery-other"},{"actor":"owner","do":"click","testid":"notification-settings","unlessVisible":"notification-order"},{"actor":"owner","do":"click","testid":"notification-order"},{"actor":"owner","do":"click","testid":"notification-save"},{"actor":"owner","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"owner","do":"click","testid":"catalog-link"},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"action":"buy","actor":"owner","do":"callAction","input":{"attribute":"data-buy-input","contains":"Desk Lamp","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"}},{"actor":"owner","do":"expectActionOutcome","outcome":"accepted"},{"actor":"owner","do":"reload","settleMs":1000},{"actor":"owner","do":"ensureSignedIn","name":"delivery-owner","readyTestid":"current-user"},{"actor":"owner","do":"click","testid":"notifications-toggle","unlessVisible":"notifications-panel"},{"actor":"owner","attribute":"aria-busy","do":"expect","testid":"notifications-panel","value":"false","within":10000},{"actor":"owner","contains":"Desk Lamp","do":"expectElementCount","equals":0,"testid":"notification-item"},{"actor":"owner","do":"reload","settleMs":1000},{"actor":"owner","do":"ensureSignedIn","name":"delivery-owner","readyTestid":"current-user"},{"actor":"owner","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"owner","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"as":"notification-shipped","do":"recordTime"},{"action":"ship","actor":"staff","do":"callAction","from":"owner","input":{"attribute":"data-ship-input","contains":"Desk Lamp","testid":"order-item"},"namedAction":{"args":[0],"id":"ship","params":[{"in":"body","name":"orderId","wireType":"u64"}],"path":"/api/fulfilment/ship","reducer":"ship_order"}},{"actor":"staff","do":"expectActionOutcome","outcome":"accepted"},{"as":"notification-shipped-accepted","do":"recordTime"},{"actor":"owner","do":"reload","settleMs":1000},{"actor":"owner","do":"ensureSignedIn","name":"delivery-owner","readyTestid":"current-user"},{"actor":"owner","do":"click","testid":"notifications-toggle","unlessVisible":"notifications-panel"},{"actor":"owner","attribute":"aria-busy","do":"expect","testid":"notifications-panel","value":"false","within":10000},{"atMost":40000,"do":"expectElapsed","since":"notification-shipped"},{"actor":"owner","contains":"Desk Lamp","do":"expectElementCount","equals":0,"testid":"notification-item"},{"actor":"owner","do":"wait","ms":75000,"since":"notification-shipped-accepted"},{"actor":"owner","do":"reload","settleMs":1000},{"actor":"owner","do":"ensureSignedIn","name":"delivery-owner","readyTestid":"current-user"},{"actor":"owner","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"owner","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"owner","do":"expect","ignoreCase":true,"in":{"contains":"Desk Lamp","testid":"order-item"},"testid":"order-status","value":"delivered"}]},"packId":"ecommerce.progression.delivery-notifications","requiresFeatures":["ecommerce.feature.purchasing","ecommerce.progression.fulfilment-queue"],"role":"feature","source":"scenarios/progression-delivery-notifications.json"},{"checkGroupId":"delivery-notification-privacy","feature":{"actors":["owner","other","staff"],"criteria":[{"id":"501b","steps":[{"actor":"owner","do":"reload","settleMs":1000},{"actor":"owner","do":"ensureSignedIn","name":"delivery-owner","readyTestid":"current-user"},{"actor":"owner","do":"click","testid":"notifications-toggle","unlessVisible":"notifications-panel"},{"actor":"owner","contains":"Desk Lamp","do":"expectElementCount","equals":1,"testid":"notification-item","within":10000},{"actor":"other","do":"click","testid":"notifications-toggle","unlessVisible":"notifications-panel"},{"actor":"other","attribute":"aria-busy","do":"expect","testid":"notifications-panel","value":"false","within":10000},{"absent":true,"actor":"other","contains":"Desk Lamp","do":"expect","testid":"notification-item"}]}],"id":501,"setup":[{"actor":"owner","do":"signUp","name":"delivery-owner"},{"actor":"other","do":"signUp","name":"delivery-other"},{"actor":"owner","do":"click","testid":"notification-settings","unlessVisible":"notification-order"},{"actor":"owner","do":"click","testid":"notification-order"},{"actor":"owner","do":"click","testid":"notification-save"},{"actor":"owner","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"owner","do":"click","testid":"catalog-link"},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"action":"buy","actor":"owner","do":"callAction","input":{"attribute":"data-buy-input","contains":"Desk Lamp","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"}},{"actor":"owner","do":"expectActionOutcome","outcome":"accepted"},{"actor":"owner","do":"reload","settleMs":1000},{"actor":"owner","do":"ensureSignedIn","name":"delivery-owner","readyTestid":"current-user"},{"actor":"owner","do":"click","testid":"notifications-toggle","unlessVisible":"notifications-panel"},{"actor":"owner","attribute":"aria-busy","do":"expect","testid":"notifications-panel","value":"false","within":10000},{"actor":"owner","contains":"Desk Lamp","do":"expectElementCount","equals":0,"testid":"notification-item"},{"actor":"owner","do":"reload","settleMs":1000},{"actor":"owner","do":"ensureSignedIn","name":"delivery-owner","readyTestid":"current-user"},{"actor":"owner","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"owner","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"as":"notification-shipped","do":"recordTime"},{"action":"ship","actor":"staff","do":"callAction","from":"owner","input":{"attribute":"data-ship-input","contains":"Desk Lamp","testid":"order-item"},"namedAction":{"args":[0],"id":"ship","params":[{"in":"body","name":"orderId","wireType":"u64"}],"path":"/api/fulfilment/ship","reducer":"ship_order"}},{"actor":"staff","do":"expectActionOutcome","outcome":"accepted"},{"as":"notification-shipped-accepted","do":"recordTime"},{"actor":"owner","do":"reload","settleMs":1000},{"actor":"owner","do":"ensureSignedIn","name":"delivery-owner","readyTestid":"current-user"},{"actor":"owner","do":"click","testid":"notifications-toggle","unlessVisible":"notifications-panel"},{"actor":"owner","attribute":"aria-busy","do":"expect","testid":"notifications-panel","value":"false","within":10000},{"atMost":40000,"do":"expectElapsed","since":"notification-shipped"},{"actor":"owner","contains":"Desk Lamp","do":"expectElementCount","equals":0,"testid":"notification-item"},{"actor":"owner","do":"wait","ms":75000,"since":"notification-shipped-accepted"},{"actor":"owner","do":"reload","settleMs":1000},{"actor":"owner","do":"ensureSignedIn","name":"delivery-owner","readyTestid":"current-user"},{"actor":"owner","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"owner","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"owner","do":"expect","ignoreCase":true,"in":{"contains":"Desk Lamp","testid":"order-item"},"testid":"order-status","value":"delivered"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","requiresFeatures":["ecommerce.feature.purchasing","ecommerce.progression.delivery-notifications","ecommerce.progression.fulfilment-queue"],"role":"guarantee","source":"scenarios/progression-delivery-notifications.json"}],"id":"selected-source-074","scenario":{"level":5,"writeUrlPattern":null},"source":"scenarios/progression-delivery-notifications.json"},{"checkGroups":[{"checkGroupId":"faceted-search","feature":{"actors":["visitor"],"criteria":[{"id":"401a","steps":[{"actor":"visitor","contains":"Coffee Grinder","do":"expectElementCount","equals":1,"in":{"testid":"search-results"},"testid":"item-card","within":10000},{"actor":"visitor","do":"click","testid":"in-stock-filter"},{"actor":"visitor","do":"click","ifAvailable":true,"testid":"filter-apply"},{"actor":"visitor","contains":"Coffee Grinder","do":"waitUntilAbsent","in":{"testid":"search-results"},"testid":"item-card","within":10000},{"actor":"visitor","contains":"Air Purifier","do":"expectElementCount","equals":1,"in":{"testid":"search-results"},"testid":"item-card"},{"absent":true,"actor":"visitor","contains":"USB Cable","do":"expect","in":{"testid":"search-results"},"testid":"item-card"},{"absent":true,"actor":"visitor","contains":"Desk Lamp","do":"expect","in":{"testid":"search-results"},"testid":"item-card"},{"absent":true,"actor":"visitor","contains":"Espresso Machine","do":"expect","in":{"testid":"search-results"},"testid":"item-card"},{"absent":true,"actor":"visitor","contains":"Gaming Mouse","do":"expect","in":{"testid":"search-results"},"testid":"item-card"}]}],"id":401,"setup":[{"do":"dbSetStock","item":"Coffee Grinder","quantity":0,"settleMs":0,"warehouse":"East"},{"do":"dbSetStock","item":"Coffee Grinder","quantity":0,"settleMs":1000,"warehouse":"West"},{"actor":"visitor","do":"reload","settleMs":1000},{"actor":"visitor","do":"fill","testid":"category-filter","text":"Home"},{"actor":"visitor","do":"fill","testid":"minimum-price","text":"50"},{"actor":"visitor","do":"fill","testid":"maximum-price","text":"200"},{"actor":"visitor","do":"click","ifAvailable":true,"testid":"filter-apply"}]},"packId":"ecommerce.progression.faceted-search","role":"feature","source":"scenarios/progression-faceted-filters.json"}],"id":"selected-source-075","scenario":{"level":3,"writeUrlPattern":null},"source":"scenarios/progression-faceted-filters.json"},{"checkGroups":[{"checkGroupId":"faceted-search","feature":{"actors":["visitor"],"criteria":[{"id":"402a","steps":[{"actor":"visitor","do":"expectSequence","equals":["Air Purifier","Bluetooth Speaker","Coffee Grinder","Desk Lamp","Espresso Machine","Gaming Mouse","Headphones","Induction Cooktop","Keyboard","Laptop Stand"],"in":{"testid":"search-results"},"testid":"item-name"},{"actor":"visitor","do":"click","testid":"search-next-page"},{"actor":"visitor","do":"expectSequence","equals":["Mirrorless Camera","USB Cable","Webcam"],"in":{"testid":"search-results"},"testid":"item-name"},{"actor":"visitor","do":"click","testid":"search-previous-page"},{"actor":"visitor","do":"expectSequence","equals":["Air Purifier","Bluetooth Speaker","Coffee Grinder","Desk Lamp","Espresso Machine","Gaming Mouse","Headphones","Induction Cooktop","Keyboard","Laptop Stand"],"in":{"testid":"search-results"},"testid":"item-name"}]}],"id":402,"setup":[{"actor":"visitor","do":"fill","testid":"minimum-price","text":"1"},{"actor":"visitor","do":"click","ifAvailable":true,"testid":"filter-apply"}]},"packId":"ecommerce.progression.faceted-search","role":"feature","source":"scenarios/progression-faceted-pagination.json"}],"id":"selected-source-076","scenario":{"level":3,"writeUrlPattern":null},"source":"scenarios/progression-faceted-pagination.json"},{"checkGroups":[{"checkGroupId":"managed-support-privacy","feature":{"actors":["owner","other","staff"],"criteria":[{"id":"613b","steps":[{"actor":"owner","do":"reload","settleMs":1000},{"actor":"owner","do":"ensureSignedIn","name":"managed-private-owner","readyTestid":"current-user"},{"actor":"owner","do":"click","testid":"support-link"},{"actor":"owner","contains":"Private managed case {user:casemarker}","do":"expect","testid":"support-ticket"},{"actor":"owner","contains":"Private managed case {user:casemarker}","do":"expectReceived","within":10000},{"absent":true,"actor":"other","contains":"Private managed case {user:casemarker}","do":"expect","testid":"support-ticket"},{"actor":"other","contains":"Private managed case {user:casemarker}","do":"expectNotReceived"},{"actor":"owner","do":"fill","in":{"contains":"Private managed case {user:casemarker}","testid":"support-ticket"},"testid":"support-reply","text":"Owner-only update"},{"actor":"owner","do":"click","in":{"contains":"Private managed case {user:casemarker}","testid":"support-ticket"},"testid":"support-reply-submit"},{"actor":"other","do":"replayAs","from":"owner","match":"Owner-only update","namedAction":{"args":[0,"Owner-only update"],"id":"replySupport","method":"POST","params":[{"in":"path","name":"ticketId","placeholder":":id","wireType":"u64"},{"in":"body","name":"body"}],"path":"/api/support/:id/replies","reducer":"reply_support"},"namedTarget":{"attribute":"data-entity-id","contains":"Private managed case {user:casemarker}","testid":"support-ticket","valueType":"string"},"settleMs":1500},{"actor":"other","allowNotFound":true,"do":"expectReplayRejected"},{"actor":"staff","do":"reload","settleMs":2000},{"actor":"staff","do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026","readyTestid":"current-user"},{"actor":"staff","do":"click","ifAvailable":true,"testid":"staff-link","unlessVisible":"support-assignee"},{"actor":"staff","do":"click","ifAvailable":true,"testid":"support-queue-link","unlessVisible":"support-assignee"},{"actor":"staff","contains":"Private managed case {user:casemarker}","do":"expect","testid":"support-ticket"},{"actor":"staff","contains":"Owner-only update","do":"expectElementCount","equals":1,"testid":"support-reply-item","within":10000},{"actor":"staff","contains":"Owner-only update","do":"expectReceived","within":10000},{"actor":"other","contains":"Owner-only update","do":"expectNotReceived"}]}],"id":613,"setup":[{"actor":"owner","do":"signUp","name":"managed-private-owner"},{"actor":"owner","do":"click","testid":"support-link"},{"actor":"owner","do":"fill","testid":"support-email","text":"managed-private@example.com"},{"actor":"owner","do":"fill","testid":"support-subject","text":"Private managed case {user:casemarker}"},{"actor":"owner","do":"fill","testid":"support-message","text":"Private case details."},{"actor":"owner","do":"click","testid":"support-submit"},{"actor":"owner","do":"expect","nonEmpty":true,"testid":"support-reference"},{"actor":"other","do":"signUp","name":"managed-private-other"},{"actor":"other","do":"click","testid":"support-link"},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"staff","do":"click","testid":"staff-link","unlessVisible":"support-assignee"},{"actor":"staff","do":"click","ifAvailable":true,"testid":"support-queue-link","unlessVisible":"support-assignee"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","requiresFeatures":["ecommerce.progression.managed-support"],"role":"guarantee","source":"scenarios/progression-managed-support-privacy.json"}],"id":"selected-source-077","scenario":{"level":3,"writeUrlPattern":null},"source":"scenarios/progression-managed-support-privacy.json"},{"checkGroups":[{"checkGroupId":"managed-support","feature":{"actors":["owner","staff"],"criteria":[{"id":"613c","steps":[{"actor":"staff","do":"fill","in":{"contains":"Shared managed case","testid":"support-ticket"},"testid":"support-status-input","text":"in progress"},{"actor":"staff","do":"click","in":{"contains":"Shared managed case","testid":"support-ticket"},"settleMs":1500,"testid":"support-update"},{"actor":"staff","do":"fill","in":{"contains":"Shared managed case","testid":"support-ticket"},"testid":"support-reply","text":"Case received."},{"actor":"staff","do":"click","in":{"contains":"Shared managed case","testid":"support-ticket"},"testid":"support-reply-submit"},{"actor":"owner","do":"reload","settleMs":2000},{"actor":"owner","do":"ensureSignedIn","name":"managed-shared-owner","readyTestid":"current-user"},{"actor":"owner","do":"click","testid":"support-link"},{"actor":"owner","contains":"in progress","do":"expect","in":{"contains":"Shared managed case","testid":"support-ticket"},"testid":"support-status"},{"actor":"owner","contains":"Case received.","do":"expect","in":{"contains":"Shared managed case","testid":"support-ticket"},"testid":"support-reply-item"},{"actor":"owner","do":"fill","in":{"contains":"Shared managed case","testid":"support-ticket"},"testid":"support-reply","text":"Thank you."},{"actor":"owner","do":"click","in":{"contains":"Shared managed case","testid":"support-ticket"},"testid":"support-reply-submit"},{"actor":"staff","do":"reload","settleMs":2000},{"actor":"staff","do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026","readyTestid":"current-user"},{"actor":"staff","do":"click","testid":"staff-link","unlessVisible":"support-assignee"},{"actor":"staff","do":"click","ifAvailable":true,"testid":"support-queue-link","unlessVisible":"support-assignee"},{"actor":"staff","contains":"Thank you.","do":"expect","in":{"contains":"Shared managed case","testid":"support-ticket"},"testid":"support-reply-item"}]}],"id":613,"setup":[{"actor":"owner","do":"signUp","name":"managed-shared-owner"},{"actor":"owner","do":"click","testid":"support-link"},{"actor":"owner","do":"fill","testid":"support-email","text":"managed-shared@example.com"},{"actor":"owner","do":"fill","testid":"support-subject","text":"Shared managed case"},{"actor":"owner","do":"fill","testid":"support-message","text":"Please investigate this case."},{"actor":"owner","do":"click","testid":"support-submit"},{"actor":"owner","do":"expect","nonEmpty":true,"testid":"support-reference"},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"staff","do":"click","testid":"staff-link","unlessVisible":"support-assignee"},{"actor":"staff","do":"click","ifAvailable":true,"testid":"support-queue-link","unlessVisible":"support-assignee"}]},"packId":"ecommerce.progression.managed-support","role":"feature","source":"scenarios/progression-managed-support-shared.json"},{"checkGroupId":"managed-support","feature":{"actors":["owner","staff"],"criteria":[{"id":"613a","steps":[{"actor":"staff","do":"fill","in":{"contains":"Shared managed case","testid":"support-ticket"},"testid":"support-status-input","text":"open"},{"actor":"staff","do":"click","in":{"contains":"Shared managed case","testid":"support-ticket"},"testid":"support-update"},{"actor":"staff","contains":"open","do":"expect","in":{"contains":"Shared managed case","testid":"support-ticket"},"testid":"support-status"},{"actor":"owner","do":"reload","settleMs":1000},{"actor":"owner","do":"ensureSignedIn","name":"managed-shared-owner","readyTestid":"current-user"},{"actor":"owner","do":"click","testid":"support-link","unlessVisible":"support-ticket"},{"actor":"owner","contains":"open","do":"expect","in":{"contains":"Shared managed case","testid":"support-ticket"},"testid":"support-status"},{"actor":"staff","do":"fill","in":{"contains":"Shared managed case","testid":"support-ticket"},"testid":"support-status-input","text":"in progress"},{"actor":"staff","do":"click","in":{"contains":"Shared managed case","testid":"support-ticket"},"settleMs":1500,"testid":"support-update"},{"actor":"staff","do":"fill","in":{"contains":"Shared managed case","testid":"support-ticket"},"testid":"support-reply","text":"We are investigating."},{"actor":"staff","do":"click","in":{"contains":"Shared managed case","testid":"support-ticket"},"testid":"support-reply-submit"},{"actor":"owner","contains":"in progress","do":"expect","in":{"contains":"Shared managed case","testid":"support-ticket"},"testid":"support-status","within":10000},{"actor":"owner","contains":"We are investigating.","do":"expect","in":{"contains":"Shared managed case","testid":"support-ticket"},"testid":"support-reply-item","within":10000},{"actor":"owner","do":"fill","in":{"contains":"Shared managed case","testid":"support-ticket"},"testid":"support-reply","text":"Thank you for the update."},{"actor":"owner","do":"click","in":{"contains":"Shared managed case","testid":"support-ticket"},"testid":"support-reply-submit"},{"actor":"staff","contains":"Thank you for the update.","do":"expect","in":{"contains":"Shared managed case","testid":"support-ticket"},"testid":"support-reply-item","within":10000}]}],"id":613,"setup":[{"actor":"owner","do":"signUp","name":"managed-shared-owner"},{"actor":"owner","do":"click","testid":"support-link"},{"actor":"owner","do":"fill","testid":"support-email","text":"managed-shared@example.com"},{"actor":"owner","do":"fill","testid":"support-subject","text":"Shared managed case"},{"actor":"owner","do":"fill","testid":"support-message","text":"Please investigate this case."},{"actor":"owner","do":"click","testid":"support-submit"},{"actor":"owner","do":"expect","nonEmpty":true,"testid":"support-reference"},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"staff","do":"click","testid":"staff-link","unlessVisible":"support-assignee"},{"actor":"staff","do":"click","ifAvailable":true,"testid":"support-queue-link","unlessVisible":"support-assignee"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.live-state","requiresFeatures":["ecommerce.progression.managed-support"],"role":"guarantee","source":"scenarios/progression-managed-support-shared.json"}],"id":"selected-source-078","scenario":{"level":3,"writeUrlPattern":null},"source":"scenarios/progression-managed-support-shared.json"},{"checkGroups":[{"checkGroupId":"notification-preferences","feature":{"actors":["owner","other"],"criteria":[{"id":"630c","steps":[{"actor":"owner","do":"click","ifAvailable":true,"testid":"overlay-close"},{"actor":"owner","do":"click","ifAvailable":true,"testid":"catalog-link"},{"actor":"owner","do":"click","testid":"notification-settings","unlessVisible":"notification-order"},{"actor":"owner","attribute":"data-state","do":"expect","testid":"notification-order","value":"on"}]}],"id":630,"setup":[{"actor":"owner","do":"signUp","name":"notification-owner"},{"actor":"other","do":"signUp","name":"notification-other"},{"actor":"owner","do":"click","testid":"notification-settings","unlessVisible":"notification-order"},{"actor":"owner","do":"click","testid":"notification-order"},{"actor":"owner","do":"click","testid":"notification-save"}]},"packId":"ecommerce.progression.notification-preferences","role":"feature","source":"scenarios/progression-notification-preferences.json"},{"checkGroupId":"notification-preferences-reload","feature":{"actors":["owner","other"],"criteria":[{"id":"630a","steps":[{"actor":"owner","do":"reload","settleMs":3000},{"actor":"owner","do":"ensureSignedIn","name":"notification-owner","readyTestid":"current-user"},{"actor":"owner","do":"click","testid":"notification-settings","unlessVisible":"notification-order"},{"actor":"owner","attribute":"data-state","do":"expect","testid":"notification-order","value":"on"},{"do":"restartBackend","settleMs":1000},{"actor":"owner","do":"freshClient"},{"actor":"owner-fresh","do":"signIn","name":"notification-owner"},{"actor":"owner-fresh","do":"click","testid":"notification-settings","unlessVisible":"notification-order"},{"actor":"owner-fresh","attribute":"data-state","do":"expect","testid":"notification-order","value":"on"}]}],"id":630,"setup":[{"actor":"owner","do":"signUp","name":"notification-owner"},{"actor":"other","do":"signUp","name":"notification-other"},{"actor":"owner","do":"click","testid":"notification-settings","unlessVisible":"notification-order"},{"actor":"owner","do":"click","testid":"notification-order"},{"actor":"owner","do":"click","testid":"notification-save"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.state-durability","requiresFeatures":["ecommerce.progression.notification-preferences"],"role":"guarantee","source":"scenarios/progression-notification-preferences.json"},{"checkGroupId":"notification-preferences-privacy","feature":{"actors":["owner","other"],"criteria":[{"id":"630b","steps":[{"actor":"other","do":"click","testid":"notification-settings","unlessVisible":"notification-order"},{"actor":"other","attribute":"data-state","do":"expect","testid":"notification-order","value":"off"}]}],"id":630,"setup":[{"actor":"owner","do":"signUp","name":"notification-owner"},{"actor":"other","do":"signUp","name":"notification-other"},{"actor":"owner","do":"click","testid":"notification-settings","unlessVisible":"notification-order"},{"actor":"owner","do":"click","testid":"notification-order"},{"actor":"owner","do":"click","testid":"notification-save"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","requiresFeatures":["ecommerce.progression.notification-preferences"],"role":"guarantee","source":"scenarios/progression-notification-preferences.json"}],"id":"selected-source-079","scenario":{"level":5,"writeUrlPattern":null},"source":"scenarios/progression-notification-preferences.json"},{"checkGroups":[{"checkGroupId":"open-list","feature":{"actors":["reader","reviewer"],"criteria":[{"id":"902a","steps":[{"actor":"reader","do":"openItem","item":"Keyboard"},{"actor":"reader","do":"expect","testid":"item-detail","within":10000},{"actor":"reviewer","do":"click","ifAvailable":true,"testid":"review-toggle","unlessVisible":"review-rating"},{"actor":"reviewer","do":"fill","testid":"review-input","text":"live-review-kbd"},{"actor":"reviewer","do":"click","testid":"review-submit"},{"actor":"reviewer","contains":"live-review-kbd","do":"expectElementCount","equals":1,"testid":"review-item","within":10000},{"actor":"reader","contains":"live-review-kbd","do":"expectElementCount","equals":1,"testid":"review-item","within":10000}]}],"id":902,"setup":[{"actor":"reviewer","do":"signUp","name":"raceR"},{"actor":"reader","do":"signUp","name":"raceL"},{"action":"buy","actor":"reviewer","do":"callAction","input":{"attribute":"data-buy-input","contains":"Keyboard","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"}},{"actor":"reviewer","do":"expectActionOutcome","outcome":"accepted"},{"actor":"reviewer","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"reviewer","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"reviewer","contains":"Keyboard","do":"expect","testid":"order-item","within":10000},{"actor":"reviewer","do":"click","ifAvailable":true,"testid":"overlay-close"},{"actor":"reviewer","do":"click","ifAvailable":true,"testid":"catalog-link"},{"actor":"reviewer","do":"openItem","item":"Keyboard"},{"actor":"reviewer","do":"expect","testid":"item-detail","within":10000},{"actor":"reviewer","do":"click","ifAvailable":true,"testid":"review-toggle","unlessVisible":"review-rating"},{"actor":"reviewer","do":"fill","testid":"review-rating","text":"5"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.live-state","requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.reviews"],"role":"guarantee","source":"scenarios/progression-open-list-live.json"}],"id":"selected-source-080","scenario":{"level":1,"writeUrlPattern":null},"source":"scenarios/progression-open-list-live.json"},{"checkGroups":[{"checkGroupId":"cancellation-and-return","feature":{"actors":["customer"],"criteria":[{"id":"3e","steps":[{"absent":true,"actor":"customer","do":"expect","in":{"contains":"Desk Lamp","testid":"order-item"},"testid":"return-item"}]}],"id":331,"setup":[{"actor":"customer","do":"signUp","name":"return-boundary"},{"action":"buy","actor":"customer","do":"callAction","input":{"attribute":"data-buy-input","contains":"Desk Lamp","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"}},{"actor":"customer","do":"expectActionOutcome","outcome":"accepted"},{"actor":"customer","do":"reload","settleMs":1000},{"actor":"customer","do":"ensureSignedIn","name":"return-boundary","readyTestid":"current-user"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"customer","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"customer","do":"expect","ignoreCase":true,"in":{"contains":"Desk Lamp","testid":"order-item"},"testid":"order-status","value":"pending"}]},"packId":"ecommerce.l3.order-returns-features","requiresFeatures":["ecommerce.feature.purchasing","ecommerce.progression.fulfilment-queue"],"role":"feature","source":"scenarios/progression-order-return-boundary.json","stablePackId":"ecommerce.returns-pricing"},{"checkGroupId":"cancellation-and-return","feature":{"actors":["customer","staff","admin"],"criteria":[{"id":"3f","steps":[{"action":"returnItem","actor":"customer","do":"callAction","input":{"attribute":"data-return-input","contains":"Desk Lamp","testid":"order-line"},"namedAction":{"args":[0,0],"id":"returnItem","method":"POST","params":[{"in":"path","name":"orderId","placeholder":"{orderId}","wireType":"u64"},{"in":"path","name":"itemId","placeholder":"{itemId}","wireType":"u64"}],"path":"/api/orders/{orderId}/items/{itemId}/return","reducer":"return_order_item"}},{"actor":"customer","do":"expectActionOutcome","outcome":"validation-refused"},{"actor":"customer","do":"reload","settleMs":1000},{"actor":"customer","do":"ensureSignedIn","name":"return-boundary","readyTestid":"current-user"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"customer","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"customer","do":"expect","ignoreCase":true,"in":{"contains":"Desk Lamp","testid":"order-item"},"testid":"order-status","value":"pending"},{"do":"dbExpectStock","item":"Desk Lamp","plus":0,"relativeTo":"pending-East","warehouse":"East"},{"do":"dbExpectStock","item":"Desk Lamp","plus":0,"relativeTo":"pending-West","warehouse":"West"},{"actor":"admin","do":"reload","settleMs":1000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"admin","do":"click","testid":"admin-link","unlessVisible":"admin-revenue"},{"actor":"admin","do":"expectNumber","plus":0,"relativeTo":"pending-revenue","testid":"admin-revenue"}]}],"id":332,"setup":[{"actor":"customer","do":"signUp","name":"return-boundary"},{"action":"buy","actor":"customer","do":"callAction","input":{"attribute":"data-buy-input","contains":"Desk Lamp","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"}},{"actor":"customer","do":"expectActionOutcome","outcome":"accepted"},{"actor":"customer","do":"reload","settleMs":1000},{"actor":"customer","do":"ensureSignedIn","name":"return-boundary","readyTestid":"current-user"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"customer","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"customer","do":"expect","ignoreCase":true,"in":{"contains":"Desk Lamp","testid":"order-item"},"testid":"order-status","value":"pending"},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"customer","do":"reload","settleMs":1000},{"actor":"customer","do":"ensureSignedIn","name":"return-boundary","readyTestid":"current-user"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"customer","do":"click","testid":"catalog-link","unlessVisible":"item-card"},{"action":"buy","actor":"customer","do":"callAction","input":{"attribute":"data-buy-input","contains":"Keyboard","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"}},{"actor":"customer","do":"expectActionOutcome","outcome":"accepted"},{"actor":"customer","do":"reload","settleMs":1000},{"actor":"customer","do":"ensureSignedIn","name":"return-boundary","readyTestid":"current-user"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"customer","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"action":"ship","actor":"staff","do":"callAction","from":"customer","input":{"attribute":"data-ship-input","contains":"Keyboard","testid":"order-item"},"namedAction":{"args":[0],"id":"ship","params":[{"in":"body","name":"orderId","wireType":"u64"}],"path":"/api/fulfilment/ship","reducer":"ship_order"}},{"actor":"staff","do":"expectActionOutcome","outcome":"accepted"},{"actor":"customer","do":"reload","settleMs":1000},{"actor":"customer","do":"ensureSignedIn","name":"return-boundary","readyTestid":"current-user"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"customer","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"customer","do":"expect","ignoreCase":true,"in":{"contains":"Keyboard","testid":"order-item"},"testid":"order-status","value":"shipped"},{"action":"returnItem","actor":"customer","do":"callAction","input":{"attribute":"data-return-input","contains":"Keyboard","testid":"order-line"},"namedAction":{"args":[0,0],"id":"returnItem","method":"POST","params":[{"in":"path","name":"orderId","placeholder":"{orderId}","wireType":"u64"},{"in":"path","name":"itemId","placeholder":"{itemId}","wireType":"u64"}],"path":"/api/orders/{orderId}/items/{itemId}/return","reducer":"return_order_item"}},{"actor":"customer","do":"expectActionOutcome","outcome":"accepted"},{"actor":"customer","do":"reload","settleMs":1000},{"actor":"customer","do":"ensureSignedIn","name":"return-boundary","readyTestid":"current-user"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"customer","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"customer","do":"expect","ignoreCase":true,"in":{"contains":"Keyboard","testid":"order-item"},"testid":"order-status","value":"returned"},{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"click","testid":"admin-link"},{"actor":"admin","as":"pending-revenue","do":"recordNumber","testid":"admin-revenue"},{"as":"pending-East","do":"dbRecordStock","item":"Desk Lamp","warehouse":"East"},{"as":"pending-West","do":"dbRecordStock","item":"Desk Lamp","warehouse":"West"},{"actor":"customer","do":"expect","ignoreCase":true,"in":{"contains":"Desk Lamp","testid":"order-item"},"testid":"order-status","value":"pending"}]},"packId":"ecommerce.l3.order-returns-features","requiresFeatures":["ecommerce.feature.purchasing","ecommerce.progression.fulfilment-queue"],"role":"feature","source":"scenarios/progression-order-return-boundary.json","stablePackId":"ecommerce.returns-pricing"}],"id":"selected-source-081","scenario":{"level":3,"writeUrlPattern":null},"source":"scenarios/progression-order-return-boundary.json"},{"checkGroups":[{"checkGroupId":"cancellation-and-return","feature":{"actors":["customer","staff","admin"],"criteria":[{"id":"3c","steps":[{"actor":"customer","do":"click","in":{"contains":"Keyboard","testid":"order-item"},"testid":"return-item"},{"actor":"customer","contains":"Keyboard","containsText":"returned","do":"expect","ignoreCase":true,"testid":"order-item","within":10000},{"actor":"customer","do":"freshClient"},{"actor":"customer-fresh","do":"signIn","name":"return-complete"},{"actor":"customer-fresh","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"customer-fresh","do":"click","testid":"orders-toggle"},{"actor":"customer-fresh","contains":"Keyboard","containsText":"returned","do":"expect","ignoreCase":true,"testid":"order-item","within":10000},{"actor":"admin","do":"reload","settleMs":1000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","testid":"admin-link","unlessVisible":"admin-revenue"},{"actor":"admin","do":"expectNumber","plus":0,"relativeTo":"return-revenue-before","testid":"admin-revenue","within":10000},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"customer","do":"click","ifAvailable":true,"testid":"catalog-link","within":1000},{"do":"dbExpectStock","item":"Keyboard","plus":0,"relativeTo":"return-stock-before"}]}],"id":330,"setup":[{"actor":"customer","do":"signUp","name":"return-complete"},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"staff","do":"click","testid":"staff-link"},{"actor":"admin","do":"click","testid":"admin-link"},{"actor":"customer","do":"expectNumber","equals":89,"in":{"contains":"Keyboard","testid":"item-card"},"testid":"item-price"},{"as":"return-stock-before","do":"dbRecordStock","item":"Keyboard"},{"actor":"admin","as":"return-revenue-before","do":"recordNumber","testid":"admin-revenue"},{"actor":"customer","do":"click","in":{"contains":"Keyboard","testid":"item-card"},"testid":"buy-now"},{"actor":"staff","do":"reload","settleMs":1000},{"actor":"staff","do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026","readyTestid":"current-user"},{"actor":"staff","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"staff","do":"click","testid":"staff-link","unlessVisible":"queue-item"},{"actor":"staff","contains":"Keyboard","do":"expect","testid":"queue-item","within":10000},{"do":"dbExpectStock","item":"Keyboard","plus":-1,"relativeTo":"return-stock-before"},{"actor":"admin","do":"reload","settleMs":1000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"admin","do":"click","testid":"admin-link","unlessVisible":"admin-revenue"},{"actor":"admin","do":"expectNumber","plus":89,"relativeTo":"return-revenue-before","testid":"admin-revenue","within":10000},{"actor":"staff","do":"click","in":{"contains":"Keyboard","testid":"queue-item"},"testid":"ship-submit"},{"actor":"customer","do":"reload","settleMs":1000},{"actor":"customer","do":"ensureSignedIn","name":"return-complete","readyTestid":"current-user"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"customer","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"customer","do":"expect","ignoreCase":true,"in":{"contains":"Keyboard","testid":"order-item"},"testid":"order-status","value":"shipped","within":10000}]},"packId":"ecommerce.l3.order-returns-features","requiresFeatures":["ecommerce.feature.purchasing","ecommerce.progression.fulfilment-queue"],"role":"feature","source":"scenarios/progression-order-return-complete.json","stablePackId":"ecommerce.returns-pricing"}],"id":"selected-source-082","scenario":{"level":3,"writeUrlPattern":null},"source":"scenarios/progression-order-return-complete.json"},{"checkGroups":[{"checkGroupId":"order-support-ownership","feature":{"actors":["owner","other"],"criteria":[{"id":"614b","steps":[{"absent":true,"actor":"other","contains":"Desk Lamp","do":"expect","testid":"support-order-option"},{"action":"linkSupportOrder","actor":"owner","authentication":"actor","do":"callAction","input":{"attribute":"data-action-input","testid":"support-link-order"},"namedAction":{"args":[0,0],"id":"linkSupportOrder","method":"POST","params":[{"in":"path","name":"caseId","placeholder":"{caseId}","wireType":"u64"},{"in":"body","name":"orderId","wireType":"u64"}],"path":"/api/support/cases/{caseId}/order","reducer":"link_support_order"},"settleMs":1500},{"actor":"owner","do":"expectActionOutcome","outcome":"accepted"},{"actor":"owner","contains":"Desk Lamp","do":"expectElementCount","equals":1,"testid":"support-order","within":10000},{"action":"linkSupportOrder","actor":"other","authentication":"actor","do":"callAction","from":"owner","input":{"attribute":"data-action-input","overrides":{"caseId":{"actor":"other","attribute":"data-entity-id","contains":"Other order case","testid":"support-ticket"}},"testid":"support-link-order"},"namedAction":{"args":[0,0],"id":"linkSupportOrder","method":"POST","params":[{"in":"path","name":"caseId","placeholder":"{caseId}","wireType":"u64"},{"in":"body","name":"orderId","wireType":"u64"}],"path":"/api/support/cases/{caseId}/order","reducer":"link_support_order"},"settleMs":1500},{"actor":"other","do":"expectActionOutcome","outcome":"refused"},{"actor":"other","do":"freshClient"},{"actor":"other-fresh","do":"signIn","name":"order-boundary-other"},{"actor":"other-fresh","do":"click","testid":"support-link"},{"absent":true,"actor":"other-fresh","contains":"Desk Lamp","do":"expect","in":{"contains":"Other order case","testid":"support-ticket"},"testid":"support-order"},{"actor":"owner","contains":"Desk Lamp","do":"expectElementCount","equals":1,"testid":"support-order","within":10000}]}],"id":614,"setup":[{"actor":"owner","do":"signUp","name":"order-boundary-owner"},{"actor":"owner","do":"click","in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"buy-now"},{"actor":"owner","do":"click","testid":"support-link"},{"actor":"owner","do":"fill","testid":"support-subject","text":"Owner order case"},{"actor":"owner","do":"fill","testid":"support-message","text":"This case belongs to the order owner."},{"actor":"owner","do":"click","testid":"support-submit"},{"actor":"owner","contains":"Desk Lamp","do":"click","in":{"contains":"Owner order case","testid":"support-ticket"},"testid":"support-order-option"},{"actor":"other","do":"signUp","name":"order-boundary-other"},{"actor":"other","do":"click","testid":"support-link"},{"actor":"other","do":"fill","testid":"support-subject","text":"Other order case"},{"actor":"other","do":"fill","testid":"support-message","text":"This is a separate case."},{"actor":"other","do":"click","testid":"support-submit"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","requiresFeatures":["ecommerce.progression.order-support"],"role":"guarantee","source":"scenarios/progression-order-support-boundary.json"}],"id":"selected-source-083","scenario":{"level":4,"writeUrlPattern":null},"source":"scenarios/progression-order-support-boundary.json"},{"checkGroups":[{"checkGroupId":"order-support-owned","feature":{"actors":["owner","staff"],"criteria":[{"id":"614a","steps":[{"actor":"owner","contains":"Desk Lamp","do":"click","in":{"contains":"Owned order case","testid":"support-ticket"},"testid":"support-order-option"},{"actor":"owner","do":"click","in":{"contains":"Owned order case","testid":"support-ticket"},"testid":"support-link-order"},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"staff","do":"click","testid":"staff-link","unlessVisible":"support-assignee"},{"actor":"staff","do":"click","ifAvailable":true,"testid":"support-queue-link","unlessVisible":"support-assignee"},{"actor":"staff","contains":"Desk Lamp","do":"expect","in":{"contains":"Owned order case","testid":"support-ticket"},"testid":"support-order","within":10000}]}],"id":614,"setup":[{"actor":"owner","do":"signUp","name":"order-support-owner"},{"actor":"owner","do":"click","in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"buy-now"},{"actor":"owner","do":"click","testid":"support-link"},{"actor":"owner","do":"fill","testid":"support-subject","text":"Owned order case"},{"actor":"owner","do":"fill","testid":"support-message","text":"Question about my Desk Lamp order."},{"actor":"owner","do":"click","testid":"support-submit"}]},"packId":"ecommerce.progression.order-support","role":"feature","source":"scenarios/progression-order-support-owned.json"}],"id":"selected-source-084","scenario":{"level":4,"writeUrlPattern":null},"source":"scenarios/progression-order-support-owned.json"},{"checkGroups":[{"checkGroupId":"personalized-recommendations","feature":{"actors":["sales-helper","audio-customer","home-customer","computing-customer"],"criteria":[{"id":"403a","steps":[{"actor":"audio-customer","contains":"Headphones","do":"expect","in":{"testid":"recommendations"},"testid":"recommended-item"},{"actor":"home-customer","do":"expectNumber","equals":1,"in":{"contains":"Desk Lamp","testid":"recommended-item"},"testid":"recommendation-rank","within":10000},{"actor":"computing-customer","do":"expectSequence","equals":["Gaming Mouse","Laptop Stand","Webcam"],"in":{"testid":"recommendations"},"testid":"recommended-item","within":10000}]}],"id":403,"setup":[{"actor":"sales-helper","do":"signUp","name":"recommend-sales"},{"actor":"sales-helper","do":"click","in":{"contains":"Desk Lamp","testid":"item-card"},"settleMs":500,"testid":"buy-now"},{"actor":"sales-helper","do":"click","in":{"contains":"Desk Lamp","testid":"item-card"},"settleMs":500,"testid":"buy-now"},{"actor":"sales-helper","do":"click","in":{"contains":"Desk Lamp","testid":"item-card"},"settleMs":500,"testid":"buy-now"},{"actor":"audio-customer","do":"signUp","name":"recommend-audio"},{"actor":"audio-customer","do":"click","in":{"contains":"Bluetooth Speaker","testid":"item-card"},"testid":"buy-now"},{"actor":"home-customer","do":"signUp","name":"recommend-home"},{"actor":"home-customer","do":"click","in":{"contains":"Coffee Grinder","testid":"item-card"},"testid":"buy-now"},{"actor":"computing-customer","do":"signUp","name":"recommend-computing"},{"actor":"computing-customer","do":"click","in":{"contains":"Keyboard","testid":"item-card"},"testid":"buy-now"}]},"packId":"ecommerce.progression.personalized-recommendations","role":"feature","source":"scenarios/progression-personalized-recommendations.json"},{"checkGroupId":"recommendation-profile-isolation","feature":{"actors":["sales-helper","audio-customer","home-customer","computing-customer"],"criteria":[{"id":"403b","steps":[{"actor":"audio-customer","do":"click","in":{"contains":"Headphones","testid":"item-card"},"testid":"buy-now"},{"actor":"audio-customer","contains":"Headphones","do":"waitUntilAbsent","in":{"testid":"recommendations"},"testid":"recommended-item","within":10000},{"actor":"home-customer","do":"expectNumber","equals":1,"in":{"contains":"Desk Lamp","testid":"recommended-item"},"testid":"recommendation-rank","within":10000},{"actor":"computing-customer","do":"expectSequence","equals":["Gaming Mouse","Laptop Stand","Webcam"],"in":{"testid":"recommendations"},"testid":"recommended-item","within":10000}]}],"id":403,"setup":[{"actor":"sales-helper","do":"signUp","name":"recommend-sales"},{"actor":"sales-helper","do":"click","in":{"contains":"Desk Lamp","testid":"item-card"},"settleMs":500,"testid":"buy-now"},{"actor":"sales-helper","do":"click","in":{"contains":"Desk Lamp","testid":"item-card"},"settleMs":500,"testid":"buy-now"},{"actor":"sales-helper","do":"click","in":{"contains":"Desk Lamp","testid":"item-card"},"settleMs":500,"testid":"buy-now"},{"actor":"audio-customer","do":"signUp","name":"recommend-audio"},{"actor":"audio-customer","do":"click","in":{"contains":"Bluetooth Speaker","testid":"item-card"},"testid":"buy-now"},{"actor":"home-customer","do":"signUp","name":"recommend-home"},{"actor":"home-customer","do":"click","in":{"contains":"Coffee Grinder","testid":"item-card"},"testid":"buy-now"},{"actor":"computing-customer","do":"signUp","name":"recommend-computing"},{"actor":"computing-customer","do":"click","in":{"contains":"Keyboard","testid":"item-card"},"testid":"buy-now"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","requiresFeatures":["ecommerce.progression.personalized-recommendations"],"role":"guarantee","source":"scenarios/progression-personalized-recommendations.json"}],"id":"selected-source-085","scenario":{"level":4,"writeUrlPattern":null},"source":"scenarios/progression-personalized-recommendations.json"},{"checkGroups":[{"checkGroupId":"price-history","feature":{"actors":["admin","customer"],"criteria":[{"id":"4c","steps":[{"actor":"customer","do":"fill","enter":true,"settleMs":1500,"testid":"search-input","text":"Desk Lamp"},{"actor":"customer","do":"click","in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"add-to-cart"},{"actor":"customer","do":"click","testid":"cart-toggle"},{"actor":"customer","do":"expectNumber","equals":42,"testid":"cart-total"},{"actor":"admin","do":"fill","in":{"contains":"Desk Lamp","testid":"admin-item-row"},"testid":"price-input","text":"52.00"},{"actor":"admin","do":"click","in":{"contains":"Desk Lamp","testid":"admin-item-row"},"testid":"price-submit"},{"actor":"customer","do":"expectNumber","equals":52,"testid":"cart-total","within":10000},{"action":"checkout","actor":"customer","do":"callAction","namedAction":{"args":[],"id":"checkout","method":"POST","path":"/api/checkout","reducer":"checkout"},"settleMs":1500},{"actor":"customer","do":"expectActionOutcome","outcome":"accepted"},{"actor":"customer","do":"freshClient"},{"actor":"customer-fresh","do":"signIn","name":"price-cart"},{"actor":"customer-fresh","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"customer-fresh","do":"click","testid":"orders-toggle"},{"actor":"customer-fresh","contains":"Desk Lamp","count":1,"do":"expect","testid":"order-item"},{"actor":"customer-fresh","do":"expectNumber","equals":52,"in":{"contains":"Desk Lamp","testid":"order-item"},"testid":"order-total"}]}],"id":420,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"customer","do":"signUp","name":"price-cart"},{"actor":"admin","do":"click","testid":"admin-link"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.progression.price-history-specifications","requiresFeatures":["ecommerce.feature.checkout","ecommerce.l2.price-history-features"],"role":"guarantee","source":"scenarios/progression-price-cart-checkout.json","stablePackId":"ecommerce.returns-pricing"}],"id":"selected-source-086","scenario":{"level":2,"writeUrlPattern":null},"source":"scenarios/progression-price-cart-checkout.json"},{"checkGroups":[{"checkGroupId":"product-bundles","feature":{"actors":["admin","visitor"],"criteria":[{"id":"740a","steps":[{"actor":"admin","do":"fill","testid":"bundle-name-input","text":"Office bundle"},{"actor":"admin","do":"fill","testid":"bundle-price-input","text":"75.00"},{"actor":"admin","do":"fill","testid":"bundle-components-input","text":"[{\"item\":\"Keyboard\",\"quantity\":2},{\"item\":\"Desk Lamp\",\"quantity\":1}]"},{"actor":"admin","do":"click","testid":"bundle-save"},{"actor":"admin","contains":"Office bundle","do":"expect","testid":"bundle-card","within":10000},{"actor":"visitor","do":"reload","settleMs":1000},{"actor":"visitor","do":"click","testid":"bundles-link","unlessVisible":"bundle-card"},{"actor":"visitor","do":"expectNumber","equals":75,"in":{"contains":"Office bundle","testid":"bundle-card"},"testid":"bundle-price","within":10000},{"actor":"visitor","do":"expectElementCount","equals":2,"in":{"contains":"Office bundle","testid":"bundle-card"},"testid":"bundle-component"},{"actor":"visitor","attribute":"data-quantity","contains":"Keyboard","do":"expect","in":{"contains":"Office bundle","testid":"bundle-card"},"testid":"bundle-component","value":"2","within":10000},{"actor":"visitor","attribute":"data-quantity","contains":"Desk Lamp","do":"expect","in":{"contains":"Office bundle","testid":"bundle-card"},"testid":"bundle-component","value":"1","within":10000}]}],"id":740,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"click","testid":"bundles-link","unlessVisible":"bundle-name-input"}]},"packId":"ecommerce.feature.product-bundles","role":"feature","source":"scenarios/progression-product-bundles.json"},{"checkGroupId":"bundle-743","feature":{"actors":["admin","customer"],"criteria":[{"id":"743a","steps":[{"actor":"admin","do":"fill","testid":"bundle-price-input","text":"1.00"},{"action":"saveBundle","actor":"customer","do":"callAction","from":"admin","input":{"attribute":"data-bundle-save-input","testid":"bundle-save"},"namedAction":{"args":["Protected bundle",1,"[{\"item\":\"Keyboard\",\"quantity\":1}]"],"id":"saveBundle","params":[{"in":"body","name":"name"},{"in":"body","name":"price"},{"in":"body","name":"componentsJson"}],"path":"/api/bundles","reducer":"save_bundle"},"settleMs":1000},{"actor":"customer","do":"expectActionOutcome","outcome":"application-refused"},{"actor":"admin","do":"reload","settleMs":1000},{"actor":"admin","do":"click","testid":"bundles-link","unlessVisible":"bundle-card"},{"actor":"admin","do":"expectNumber","equals":75,"in":{"contains":"Protected bundle","testid":"bundle-card"},"testid":"bundle-price","within":10000},{"actor":"admin","attribute":"data-quantity","contains":"Keyboard","do":"expect","in":{"contains":"Protected bundle","testid":"bundle-card"},"testid":"bundle-component","value":"2","within":10000}]}],"id":743,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"click","testid":"bundles-link","unlessVisible":"bundle-name-input"},{"actor":"customer","do":"signUp","name":"bundle-management"},{"actor":"admin","do":"fill","testid":"bundle-name-input","text":"Protected bundle"},{"actor":"admin","do":"fill","testid":"bundle-price-input","text":"75.00"},{"actor":"admin","do":"fill","testid":"bundle-components-input","text":"[{\"item\":\"Keyboard\",\"quantity\":2},{\"item\":\"Desk Lamp\",\"quantity\":1}]"},{"actor":"admin","do":"click","testid":"bundle-save"},{"actor":"admin","contains":"Protected bundle","do":"expect","testid":"bundle-card","within":10000}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.bundle-integrity","requiresFeatures":["ecommerce.feature.product-bundles"],"role":"guarantee","source":"scenarios/progression-product-bundles.json"}],"id":"selected-source-087","scenario":{"level":4,"writeUrlPattern":null},"source":"scenarios/progression-product-bundles.json"},{"checkGroups":[{"checkGroupId":"promotion-checkout-active","feature":{"actors":["staff","activeBuyer","expiredBuyer","firstBuyer","secondBuyer"],"criteria":[{"id":"621a","steps":[{"actor":"activeBuyer","do":"click","in":{"contains":"Keyboard","testid":"item-card"},"testid":"add-to-cart"},{"actor":"activeBuyer","do":"click","testid":"cart-toggle"},{"actor":"activeBuyer","do":"fill","testid":"cart-promotion","text":"LIVE10"},{"actor":"activeBuyer","do":"click","testid":"apply-promotion"},{"actor":"activeBuyer","do":"click","testid":"checkout-submit"},{"actor":"activeBuyer","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"activeBuyer","do":"click","testid":"orders-toggle"},{"actor":"activeBuyer","do":"expectNumber","equals":8.9,"in":{"contains":"Keyboard","testid":"order-item"},"testid":"order-discount"}]}],"id":621,"setup":[{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"staff","do":"click","testid":"staff-link","unlessVisible":"promotions-link"},{"actor":"staff","do":"click","testid":"promotions-link","unlessVisible":"promotion-code"},{"actor":"staff","do":"fill","testid":"promotion-code","text":"LIVE10"},{"actor":"staff","do":"fill","testid":"promotion-discount","text":"10"},{"actor":"staff","do":"fill","testid":"promotion-start","text":"2020-01-01"},{"actor":"staff","do":"fill","testid":"promotion-end","text":"2099-12-31"},{"actor":"staff","do":"fill","testid":"promotion-limit","text":"10"},{"actor":"staff","do":"click","testid":"promotion-submit"},{"actor":"staff","do":"fill","testid":"promotion-code","text":"OLD10"},{"actor":"staff","do":"fill","testid":"promotion-discount","text":"10"},{"actor":"staff","do":"fill","testid":"promotion-start","text":"2000-01-01"},{"actor":"staff","do":"fill","testid":"promotion-end","text":"2000-12-31"},{"actor":"staff","do":"fill","testid":"promotion-limit","text":"10"},{"actor":"staff","do":"click","testid":"promotion-submit"},{"actor":"staff","do":"fill","testid":"promotion-code","text":"ONCE10"},{"actor":"staff","do":"fill","testid":"promotion-discount","text":"10"},{"actor":"staff","do":"fill","testid":"promotion-start","text":"2020-01-01"},{"actor":"staff","do":"fill","testid":"promotion-end","text":"2099-12-31"},{"actor":"staff","do":"fill","testid":"promotion-limit","text":"1"},{"actor":"staff","do":"click","testid":"promotion-submit"},{"actor":"activeBuyer","do":"signUp","name":"promotion-active"},{"actor":"expiredBuyer","do":"signUp","name":"promotion-expired"},{"actor":"firstBuyer","do":"signUp","name":"promotion-first"},{"actor":"secondBuyer","do":"signUp","name":"promotion-second"}]},"packId":"ecommerce.progression.promotion-checkout","role":"feature","source":"scenarios/progression-promotion-checkout.json"},{"checkGroupId":"promotion-checkout-expired","feature":{"actors":["staff","activeBuyer","expiredBuyer","firstBuyer","secondBuyer"],"criteria":[{"id":"621b","steps":[{"actor":"expiredBuyer","do":"click","in":{"contains":"Keyboard","testid":"item-card"},"testid":"add-to-cart"},{"actor":"expiredBuyer","do":"click","testid":"cart-toggle"},{"actor":"expiredBuyer","do":"fill","testid":"cart-promotion","text":"OLD10"},{"actor":"expiredBuyer","do":"click","testid":"apply-promotion"},{"actor":"expiredBuyer","do":"expect","testid":"promotion-error"}]}],"id":621,"setup":[{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"staff","do":"click","testid":"staff-link","unlessVisible":"promotions-link"},{"actor":"staff","do":"click","testid":"promotions-link","unlessVisible":"promotion-code"},{"actor":"staff","do":"fill","testid":"promotion-code","text":"LIVE10"},{"actor":"staff","do":"fill","testid":"promotion-discount","text":"10"},{"actor":"staff","do":"fill","testid":"promotion-start","text":"2020-01-01"},{"actor":"staff","do":"fill","testid":"promotion-end","text":"2099-12-31"},{"actor":"staff","do":"fill","testid":"promotion-limit","text":"10"},{"actor":"staff","do":"click","testid":"promotion-submit"},{"actor":"staff","do":"fill","testid":"promotion-code","text":"OLD10"},{"actor":"staff","do":"fill","testid":"promotion-discount","text":"10"},{"actor":"staff","do":"fill","testid":"promotion-start","text":"2000-01-01"},{"actor":"staff","do":"fill","testid":"promotion-end","text":"2000-12-31"},{"actor":"staff","do":"fill","testid":"promotion-limit","text":"10"},{"actor":"staff","do":"click","testid":"promotion-submit"},{"actor":"staff","do":"fill","testid":"promotion-code","text":"ONCE10"},{"actor":"staff","do":"fill","testid":"promotion-discount","text":"10"},{"actor":"staff","do":"fill","testid":"promotion-start","text":"2020-01-01"},{"actor":"staff","do":"fill","testid":"promotion-end","text":"2099-12-31"},{"actor":"staff","do":"fill","testid":"promotion-limit","text":"1"},{"actor":"staff","do":"click","testid":"promotion-submit"},{"actor":"activeBuyer","do":"signUp","name":"promotion-active"},{"actor":"expiredBuyer","do":"signUp","name":"promotion-expired"},{"actor":"firstBuyer","do":"signUp","name":"promotion-first"},{"actor":"secondBuyer","do":"signUp","name":"promotion-second"}]},"packId":"ecommerce.progression.promotion-checkout","role":"feature","source":"scenarios/progression-promotion-checkout.json"},{"checkGroupId":"promotion-checkout-exhausted","feature":{"actors":["staff","activeBuyer","expiredBuyer","firstBuyer","secondBuyer"],"criteria":[{"id":"621c","steps":[{"actor":"firstBuyer","do":"click","in":{"contains":"Keyboard","testid":"item-card"},"testid":"add-to-cart"},{"actor":"firstBuyer","do":"click","testid":"cart-toggle"},{"actor":"firstBuyer","do":"fill","testid":"cart-promotion","text":"ONCE10"},{"actor":"firstBuyer","do":"click","testid":"apply-promotion"},{"actor":"firstBuyer","do":"click","testid":"checkout-submit"},{"actor":"secondBuyer","do":"click","in":{"contains":"Keyboard","testid":"item-card"},"testid":"add-to-cart"},{"actor":"secondBuyer","do":"click","testid":"cart-toggle"},{"actor":"secondBuyer","do":"fill","testid":"cart-promotion","text":"ONCE10"},{"actor":"secondBuyer","do":"click","testid":"apply-promotion"},{"actor":"secondBuyer","do":"expect","testid":"promotion-error"}]}],"id":621,"setup":[{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"staff","do":"click","testid":"staff-link","unlessVisible":"promotions-link"},{"actor":"staff","do":"click","testid":"promotions-link","unlessVisible":"promotion-code"},{"actor":"staff","do":"fill","testid":"promotion-code","text":"LIVE10"},{"actor":"staff","do":"fill","testid":"promotion-discount","text":"10"},{"actor":"staff","do":"fill","testid":"promotion-start","text":"2020-01-01"},{"actor":"staff","do":"fill","testid":"promotion-end","text":"2099-12-31"},{"actor":"staff","do":"fill","testid":"promotion-limit","text":"10"},{"actor":"staff","do":"click","testid":"promotion-submit"},{"actor":"staff","do":"fill","testid":"promotion-code","text":"OLD10"},{"actor":"staff","do":"fill","testid":"promotion-discount","text":"10"},{"actor":"staff","do":"fill","testid":"promotion-start","text":"2000-01-01"},{"actor":"staff","do":"fill","testid":"promotion-end","text":"2000-12-31"},{"actor":"staff","do":"fill","testid":"promotion-limit","text":"10"},{"actor":"staff","do":"click","testid":"promotion-submit"},{"actor":"staff","do":"fill","testid":"promotion-code","text":"ONCE10"},{"actor":"staff","do":"fill","testid":"promotion-discount","text":"10"},{"actor":"staff","do":"fill","testid":"promotion-start","text":"2020-01-01"},{"actor":"staff","do":"fill","testid":"promotion-end","text":"2099-12-31"},{"actor":"staff","do":"fill","testid":"promotion-limit","text":"1"},{"actor":"staff","do":"click","testid":"promotion-submit"},{"actor":"activeBuyer","do":"signUp","name":"promotion-active"},{"actor":"expiredBuyer","do":"signUp","name":"promotion-expired"},{"actor":"firstBuyer","do":"signUp","name":"promotion-first"},{"actor":"secondBuyer","do":"signUp","name":"promotion-second"}]},"packId":"ecommerce.progression.promotion-checkout","role":"feature","source":"scenarios/progression-promotion-checkout.json"}],"id":"selected-source-088","scenario":{"level":5,"writeUrlPattern":null},"source":"scenarios/progression-promotion-checkout.json"},{"checkGroups":[{"checkGroupId":"promotion-report-redemptions","feature":{"actors":["staff","buyer"],"criteria":[{"id":"622a","steps":[{"actor":"staff","do":"expectNumber","equals":1,"in":{"contains":"REPORT10","testid":"promotion-report"},"testid":"promotion-redemptions"}]}],"id":622,"setup":[{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"staff","do":"click","testid":"staff-link","unlessVisible":"promotions-link"},{"actor":"staff","do":"click","testid":"promotions-link","unlessVisible":"promotion-code"},{"actor":"staff","do":"fill","testid":"promotion-code","text":"REPORT10"},{"actor":"staff","do":"fill","testid":"promotion-discount","text":"10"},{"actor":"staff","do":"fill","testid":"promotion-start","text":"2020-01-01"},{"actor":"staff","do":"fill","testid":"promotion-end","text":"2099-12-31"},{"actor":"staff","do":"fill","testid":"promotion-limit","text":"2"},{"actor":"staff","do":"click","testid":"promotion-submit"},{"actor":"buyer","do":"signUp","name":"promotion-report-buyer"},{"actor":"buyer","do":"click","in":{"contains":"Keyboard","testid":"item-card"},"testid":"add-to-cart"},{"actor":"buyer","do":"click","testid":"cart-toggle"},{"actor":"buyer","do":"fill","testid":"cart-promotion","text":"REPORT10"},{"actor":"buyer","do":"click","testid":"apply-promotion"},{"actor":"buyer","do":"click","testid":"checkout-submit"}]},"packId":"ecommerce.progression.promotion-reporting","role":"feature","source":"scenarios/progression-promotion-reporting.json"},{"checkGroupId":"promotion-report-revenue","feature":{"actors":["staff","buyer"],"criteria":[{"id":"622b","steps":[{"actor":"staff","do":"expectNumber","equals":80.1,"in":{"contains":"REPORT10","testid":"promotion-report"},"testid":"promotion-revenue"}]}],"id":622,"setup":[{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"staff","do":"click","testid":"staff-link","unlessVisible":"promotions-link"},{"actor":"staff","do":"click","testid":"promotions-link","unlessVisible":"promotion-code"},{"actor":"staff","do":"fill","testid":"promotion-code","text":"REPORT10"},{"actor":"staff","do":"fill","testid":"promotion-discount","text":"10"},{"actor":"staff","do":"fill","testid":"promotion-start","text":"2020-01-01"},{"actor":"staff","do":"fill","testid":"promotion-end","text":"2099-12-31"},{"actor":"staff","do":"fill","testid":"promotion-limit","text":"2"},{"actor":"staff","do":"click","testid":"promotion-submit"},{"actor":"buyer","do":"signUp","name":"promotion-report-buyer"},{"actor":"buyer","do":"click","in":{"contains":"Keyboard","testid":"item-card"},"testid":"add-to-cart"},{"actor":"buyer","do":"click","testid":"cart-toggle"},{"actor":"buyer","do":"fill","testid":"cart-promotion","text":"REPORT10"},{"actor":"buyer","do":"click","testid":"apply-promotion"},{"actor":"buyer","do":"click","testid":"checkout-submit"}]},"packId":"ecommerce.progression.promotion-reporting","role":"feature","source":"scenarios/progression-promotion-reporting.json"}],"id":"selected-source-089","scenario":{"level":5,"writeUrlPattern":null},"source":"scenarios/progression-promotion-reporting.json"},{"checkGroups":[{"checkGroupId":"promotion-rule-values","feature":{"actors":["staff","customer"],"criteria":[{"id":"620a","steps":[{"actor":"staff","do":"click","testid":"promotions-link","unlessVisible":"promotion-code"},{"actor":"staff","do":"fill","testid":"promotion-code","text":"SAVE10"},{"actor":"staff","do":"fill","testid":"promotion-discount","text":"10"},{"actor":"staff","do":"fill","testid":"promotion-start","text":"2099-01-01"},{"actor":"staff","do":"fill","testid":"promotion-end","text":"2099-12-31"},{"actor":"staff","do":"fill","testid":"promotion-limit","text":"2"},{"actor":"staff","do":"click","testid":"promotion-submit"},{"actor":"staff","do":"expectNumber","equals":10,"in":{"contains":"SAVE10","testid":"promotion-item"},"testid":"promotion-discount"},{"actor":"staff","contains":"2099-01-01","do":"expect","in":{"contains":"SAVE10","testid":"promotion-item"},"testid":"promotion-start"},{"actor":"staff","contains":"2099-12-31","do":"expect","in":{"contains":"SAVE10","testid":"promotion-item"},"testid":"promotion-end"},{"actor":"staff","do":"expectNumber","equals":2,"in":{"contains":"SAVE10","testid":"promotion-item"},"testid":"promotion-limit"}]}],"id":620,"setup":[{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"customer","do":"signUp","name":"promotion-customer"},{"actor":"staff","do":"click","testid":"staff-link"}]},"packId":"ecommerce.progression.promotion-rules","role":"feature","source":"scenarios/progression-promotion-rules.json"},{"checkGroupId":"promotion-management-boundary","feature":{"actors":["staff","customer"],"criteria":[{"id":"620b","steps":[{"actor":"staff","do":"click","testid":"promotions-link","unlessVisible":"promotion-code"},{"actor":"staff","do":"fill","testid":"promotion-code","text":"ACCESS10"},{"actor":"staff","do":"fill","testid":"promotion-discount","text":"10"},{"actor":"staff","do":"fill","testid":"promotion-start","text":"2099-01-01"},{"actor":"staff","do":"fill","testid":"promotion-end","text":"2099-12-31"},{"actor":"staff","do":"fill","testid":"promotion-limit","text":"2"},{"actor":"staff","do":"click","testid":"promotion-submit"},{"actor":"staff","do":"reload","settleMs":1000},{"actor":"staff","do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026","readyTestid":"current-user"},{"actor":"staff","do":"click","ifAvailable":true,"testid":"staff-link","unlessVisible":"promotion-code"},{"actor":"staff","do":"click","testid":"promotions-link","unlessVisible":"promotion-code"},{"actor":"staff","contains":"ACCESS10","do":"expect","testid":"promotion-item","within":10000},{"absent":true,"actor":"customer","do":"expect","testid":"promotions-link"},{"actor":"customer","do":"replayAs","from":"staff","match":"ACCESS10","namedAction":{"args":["ACCESS10",10,4070908800000000,4102444740000000,2],"id":"createPromotion","params":[{"in":"body","name":"code"},{"in":"body","name":"discountPercent"},{"in":"body","name":"startMicros"},{"in":"body","name":"endMicros"},{"in":"body","name":"usageLimit"}],"path":"/api/promotions","reducer":"create_promotion"},"settleMs":1500,"swap":{"find":"ACCESS10","with":"HACK10"}},{"actor":"customer","do":"expectReplayRejected"},{"absent":true,"actor":"staff","contains":"HACK10","do":"expect","testid":"promotion-item"}]}],"id":620,"setup":[{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"customer","do":"signUp","name":"promotion-customer"},{"actor":"staff","do":"click","testid":"staff-link"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","requiresFeatures":["ecommerce.progression.promotion-rules"],"role":"guarantee","source":"scenarios/progression-promotion-rules.json"}],"id":"selected-source-090","scenario":{"level":5,"writeUrlPattern":null},"source":"scenarios/progression-promotion-rules.json"},{"checkGroups":[{"checkGroupId":"purchase-order","feature":{"actors":["buyer"],"criteria":[{"id":"3c","steps":[{"actor":"buyer","do":"click","in":{"contains":"Coffee Grinder","testid":"item-card"},"testid":"buy-now"},{"actor":"buyer","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"buyer","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"buyer","contains":"Coffee Grinder","do":"expect","testid":"order-item"},{"actor":"buyer","do":"expectNumber","equals":64,"in":{"contains":"Coffee Grinder","testid":"order-item"},"testid":"order-total"}]}],"id":3,"setup":[{"actor":"buyer","do":"signUp","name":"purchase-buyer"}]},"packId":"ecommerce.feature.purchasing","role":"feature","source":"scenarios/progression-purchasing.json"}],"id":"selected-source-091","scenario":{"level":1,"writeUrlPattern":null},"source":"scenarios/progression-purchasing.json"},{"checkGroups":[{"checkGroupId":"recommendation-feedback","feature":{"actors":["customer","other"],"criteria":[{"id":"504a","steps":[{"absent":true,"actor":"customer","contains":"Headphones","do":"expect","testid":"recommended-item","within":10000}]}],"id":504,"setup":[{"actor":"customer","do":"signUp","name":"feedback-owner"},{"actor":"customer","do":"click","in":{"contains":"Bluetooth Speaker","testid":"item-card"},"testid":"buy-now"},{"actor":"other","do":"signUp","name":"feedback-other"},{"actor":"other","do":"click","in":{"contains":"Bluetooth Speaker","testid":"item-card"},"testid":"buy-now"},{"actor":"customer","contains":"Headphones","do":"expect","testid":"recommended-item"},{"actor":"other","contains":"Headphones","do":"expect","testid":"recommended-item"},{"actor":"customer","do":"click","in":{"contains":"Headphones","testid":"recommended-item"},"testid":"dismiss-recommendation"}]},"packId":"ecommerce.progression.recommendation-feedback","role":"feature","source":"scenarios/progression-recommendation-feedback.json"},{"checkGroupId":"recommendation-feedback-privacy","feature":{"actors":["customer","other"],"criteria":[{"id":"504b","steps":[{"actor":"customer","contains":"Headphones","do":"waitUntilAbsent","testid":"recommended-item","within":10000},{"actor":"other","contains":"Headphones","do":"expect","testid":"recommended-item"}]}],"id":504,"setup":[{"actor":"customer","do":"signUp","name":"feedback-owner"},{"actor":"customer","do":"click","in":{"contains":"Bluetooth Speaker","testid":"item-card"},"testid":"buy-now"},{"actor":"other","do":"signUp","name":"feedback-other"},{"actor":"other","do":"click","in":{"contains":"Bluetooth Speaker","testid":"item-card"},"testid":"buy-now"},{"actor":"customer","contains":"Headphones","do":"expect","testid":"recommended-item"},{"actor":"other","contains":"Headphones","do":"expect","testid":"recommended-item"},{"actor":"customer","do":"click","in":{"contains":"Headphones","testid":"recommended-item"},"testid":"dismiss-recommendation"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","requiresFeatures":["ecommerce.progression.recommendation-feedback"],"role":"guarantee","source":"scenarios/progression-recommendation-feedback.json"},{"checkGroupId":"recommendation-feedback-restart","feature":{"actors":["customer","other"],"criteria":[{"id":"504c","steps":[{"actor":"customer","do":"reload","settleMs":3000},{"actor":"customer","do":"ensureSignedIn","name":"feedback-owner","readyTestid":"current-user"},{"absent":true,"actor":"customer","contains":"Headphones","do":"expect","testid":"recommended-item"},{"do":"restartBackend","settleMs":1000},{"actor":"customer","do":"freshClient"},{"actor":"customer-fresh","do":"signIn","name":"feedback-owner"},{"actor":"customer-fresh","do":"expect","testid":"recommendations","within":10000},{"absent":true,"actor":"customer-fresh","contains":"Headphones","do":"expect","testid":"recommended-item"}]}],"id":504,"setup":[{"actor":"customer","do":"signUp","name":"feedback-owner"},{"actor":"customer","do":"click","in":{"contains":"Bluetooth Speaker","testid":"item-card"},"testid":"buy-now"},{"actor":"other","do":"signUp","name":"feedback-other"},{"actor":"other","do":"click","in":{"contains":"Bluetooth Speaker","testid":"item-card"},"testid":"buy-now"},{"actor":"customer","contains":"Headphones","do":"expect","testid":"recommended-item"},{"actor":"other","contains":"Headphones","do":"expect","testid":"recommended-item"},{"actor":"customer","do":"click","in":{"contains":"Headphones","testid":"recommended-item"},"testid":"dismiss-recommendation"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.state-durability","requiresFeatures":["ecommerce.progression.recommendation-feedback"],"role":"guarantee","source":"scenarios/progression-recommendation-feedback.json"}],"id":"selected-source-092","scenario":{"level":5,"writeUrlPattern":null},"source":"scenarios/progression-recommendation-feedback.json"},{"checkGroups":[{"checkGroupId":"review-eligibility-direct","feature":{"actors":["owner","stranger"],"criteria":[{"id":"618a","steps":[{"action":"submitReview","actor":"owner","do":"callAction","input":{"attribute":"data-buy-input","contains":"Keyboard","testid":"item-card"},"namedAction":{"args":[0,5,"Original buyer review"],"id":"submitReview","method":"POST","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"},{"in":"body","name":"rating"},{"in":"body","name":"comment"}],"path":"/api/items/:id/reviews","reducer":"submit_review"},"settleMs":0},{"actor":"owner","do":"expectActionOutcome","outcome":"accepted"},{"action":"submitReview","actor":"stranger","do":"callAction","input":{"attribute":"data-buy-input","contains":"Keyboard","testid":"item-card"},"namedAction":{"args":[0,5,"Nonbuyer review"],"id":"submitReview","method":"POST","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"},{"in":"body","name":"rating"},{"in":"body","name":"comment"}],"path":"/api/items/:id/reviews","reducer":"submit_review"},"settleMs":0},{"actor":"stranger","do":"expectActionOutcome","outcome":"application-refused","routeProvenBy":"owner"},{"action":"submitReview","actor":"stranger","do":"callAction","input":{"attribute":"data-buy-input","contains":"Keyboard","testid":"item-card"},"namedAction":{"args":[0,5,"Forged buyer review","claim-review-owner"],"id":"submitReview","method":"POST","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"},{"in":"body","name":"rating"},{"in":"body","name":"comment"},{"in":"body","name":"username"}],"path":"/api/items/:id/reviews","reducer":"submit_review"},"settleMs":0},{"actor":"stranger","do":"expectActionOutcome","outcome":"application-refused","routeProvenBy":"owner"},{"actor":"owner","do":"freshClient"},{"actor":"owner-fresh","do":"signIn","exact":true,"name":"claim-review-owner"},{"actor":"owner-fresh","do":"openItem","item":"Keyboard"},{"actor":"owner-fresh","contains":"Original buyer review","do":"expect","testid":"review-item","within":10000},{"absent":true,"actor":"owner-fresh","contains":"Nonbuyer review","do":"expect","testid":"review-item","within":3000},{"absent":true,"actor":"owner-fresh","contains":"Forged buyer review","do":"expect","testid":"review-item","within":3000}]}],"id":618,"setup":[{"actor":"owner","do":"signUp","exact":true,"name":"claim-review-owner"},{"actor":"stranger","do":"signUp","exact":true,"name":"claim-review-stranger"},{"action":"buy","actor":"owner","do":"callAction","input":{"attribute":"data-buy-input","contains":"Keyboard","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"},"settleMs":0},{"actor":"owner","do":"expectActionOutcome","outcome":"accepted"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.progression.review-access-specifications","requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.reviews"],"role":"guarantee","source":"scenarios/progression-review-access.json"}],"id":"selected-source-093","scenario":{"level":3,"writeUrlPattern":null},"source":"scenarios/progression-review-access.json"},{"checkGroups":[{"checkGroupId":"stored-review-script","feature":{"actors":["owner","writer","reader"],"criteria":[{"id":"9180a","steps":[{"action":"submitReview","actor":"owner","do":"callAction","input":{"attribute":"data-buy-input","contains":"Keyboard","testid":"item-card"},"namedAction":{"args":[0,5,"Benign stored review"],"id":"submitReview","method":"POST","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"},{"in":"body","name":"rating"},{"in":"body","name":"comment"}],"path":"/api/items/:id/reviews","reducer":"submit_review"},"settleMs":0},{"actor":"owner","do":"expectActionOutcome","outcome":"accepted"},{"action":"submitReview","actor":"writer","do":"callAction","input":{"attribute":"data-buy-input","contains":"Keyboard","testid":"item-card"},"namedAction":{"args":[0,5,"Stored review marker "],"id":"submitReview","method":"POST","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"},{"in":"body","name":"rating"},{"in":"body","name":"comment"}],"path":"/api/items/:id/reviews","reducer":"submit_review"},"settleMs":0},{"actor":"writer","do":"expectActionOutcome","outcome":"completed","routeProvenBy":"owner"},{"actor":"owner","do":"openItem","item":"Keyboard"},{"actor":"owner","contains":"Benign stored review","do":"expect","testid":"review-item","within":10000},{"actor":"owner","do":"wait","ms":1000},{"actor":"owner","do":"expectNoScriptExecution"},{"actor":"reader","do":"freshClient"},{"actor":"reader-fresh","do":"signIn","name":"script-review-reader"},{"actor":"reader-fresh","do":"armScriptCanary"},{"actor":"reader-fresh","do":"openItem","item":"Keyboard"},{"actor":"reader-fresh","contains":"Benign stored review","do":"expect","testid":"review-item","within":10000},{"actor":"reader-fresh","do":"wait","ms":1000},{"actor":"reader-fresh","do":"expectNoScriptExecution"}]}],"id":9180,"setup":[{"actor":"owner","do":"signUp","name":"script-review-owner"},{"actor":"reader","do":"signUp","name":"script-review-reader"},{"actor":"writer","do":"signUp","name":"script-review-writer"},{"action":"buy","actor":"owner","do":"callAction","input":{"attribute":"data-buy-input","contains":"Keyboard","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"}},{"actor":"owner","do":"expectActionOutcome","outcome":"accepted"},{"action":"buy","actor":"writer","do":"callAction","input":{"attribute":"data-buy-input","contains":"Keyboard","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"}},{"actor":"writer","do":"expectActionOutcome","outcome":"accepted"},{"actor":"owner","do":"armScriptCanary"}]},"observations":["unmentioned"],"packId":"ecommerce.progression.review-access-specifications","requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.reviews"],"role":"guarantee","source":"scenarios/progression-review-script.json"}],"id":"selected-source-094","scenario":{"level":3,"writeUrlPattern":null},"source":"scenarios/progression-review-script.json"},{"checkGroups":[{"checkGroupId":"search-ordering","feature":{"actors":["visitor","buyer"],"criteria":[{"id":"402b","steps":[{"actor":"visitor","do":"expectSequence","equals":["Air Purifier","Bluetooth Speaker","Coffee Grinder","Desk Lamp","Espresso Machine","Gaming Mouse","Headphones","Induction Cooktop","Keyboard","Laptop Stand"],"in":{"testid":"search-results"},"testid":"item-name"},{"actor":"visitor","do":"fill","enter":true,"testid":"search-input","text":"e"},{"actor":"visitor","do":"fill","testid":"minimum-price","text":""},{"actor":"visitor","do":"click","ifAvailable":true,"testid":"filter-apply"},{"actor":"visitor","do":"expectSequence","equals":["Air Purifier","Bluetooth Speaker","Coffee Grinder","Desk Lamp","Espresso Machine","Gaming Mouse","Headphones","Keyboard","Mirrorless Camera","USB Cable"],"in":{"testid":"search-results"},"testid":"item-name"},{"actor":"visitor","do":"fill","enter":true,"testid":"search-input","text":""},{"actor":"visitor","do":"expectSequence","equals":["Headphones","Air Purifier","Bluetooth Speaker","Coffee Grinder","Desk Lamp","Espresso Machine","Gaming Mouse","Induction Cooktop","Keyboard","Laptop Stand"],"in":{"testid":"item-list"},"testid":"item-name"}]}],"id":402,"setup":[{"actor":"buyer","do":"signUp","name":"search-order-buyer"},{"as":"before-search-purchase","do":"dbRecordStock","item":"Headphones"},{"actor":"buyer","do":"click","in":{"contains":"Headphones","testid":"item-card"},"testid":"buy-now"},{"do":"dbExpectStock","item":"Headphones","plus":-1,"relativeTo":"before-search-purchase"},{"actor":"visitor","do":"reload","settleMs":0},{"actor":"visitor","do":"fill","testid":"minimum-price","text":"1"},{"actor":"visitor","do":"click","ifAvailable":true,"testid":"filter-apply"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.search-ordering","requiresFeatures":["ecommerce.feature.purchasing","ecommerce.progression.faceted-search"],"role":"guarantee","source":"scenarios/progression-search-ordering.json"}],"id":"selected-source-095","scenario":{"level":3,"writeUrlPattern":null},"source":"scenarios/progression-search-ordering.json"},{"checkGroups":[{"checkGroupId":"shipping-accounting","feature":{"actors":["customer","admin","staff"],"criteria":[{"id":"202e","steps":[{"as":"stock-before-purchase","do":"dbRecordStock","item":"Keyboard"},{"actor":"admin","as":"revenue-before-purchase","do":"recordNumber","testid":"admin-revenue"},{"actor":"customer","do":"click","in":{"contains":"Keyboard","testid":"item-card"},"testid":"buy-now"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"customer","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"customer","do":"expect","ignoreCase":true,"in":{"contains":"Keyboard","testid":"order-item"},"testid":"order-status","value":"pending","within":10000},{"do":"dbExpectStock","item":"Keyboard","plus":-1,"relativeTo":"stock-before-purchase"},{"actor":"admin","do":"reload","settleMs":2000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"admin-link"},{"actor":"admin","do":"expectNumber","plus":89,"relativeTo":"revenue-before-purchase","testid":"admin-revenue","within":10000},{"actor":"admin","as":"revenue-before-ship","do":"recordNumber","testid":"admin-revenue"},{"as":"East-before-ship","do":"dbRecordStock","item":"Keyboard","warehouse":"East"},{"as":"West-before-ship","do":"dbRecordStock","item":"Keyboard","warehouse":"West"},{"actor":"staff","do":"reload","settleMs":2000},{"actor":"staff","do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026","readyTestid":"current-user"},{"actor":"staff","do":"click","ifAvailable":true,"testid":"staff-link"},{"action":"ship","actor":"staff","do":"callAction","from":"customer","input":{"attribute":"data-ship-input","contains":"Keyboard","testid":"order-item"},"namedAction":{"args":[0],"id":"ship","params":[{"in":"body","name":"orderId","wireType":"u64"}],"path":"/api/fulfilment/ship","reducer":"ship_order"},"settleMs":0},{"actor":"staff","do":"expectActionOutcome","outcome":"accepted"},{"actor":"customer","do":"reload","settleMs":2000},{"actor":"customer","do":"ensureSignedIn","name":"shipping-accounting","readyTestid":"current-user"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"customer","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"customer","do":"expect","ignoreCase":true,"in":{"contains":"Keyboard","testid":"order-item"},"testid":"order-status","value":"shipped","within":10000},{"do":"dbExpectStock","item":"Keyboard","plus":0,"relativeTo":"East-before-ship","warehouse":"East"},{"do":"dbExpectStock","item":"Keyboard","plus":0,"relativeTo":"West-before-ship","warehouse":"West"},{"actor":"admin","do":"reload","settleMs":2000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"admin-link"},{"actor":"admin","do":"expectNumber","plus":0,"relativeTo":"revenue-before-ship","testid":"admin-revenue","within":10000}]}],"id":202,"setup":[{"actor":"customer","do":"signUp","name":"shipping-accounting"},{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"click","testid":"admin-link"},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"staff","do":"click","testid":"staff-link"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.progression.inventory-conservation-specifications","requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.warehouse-admin","ecommerce.progression.fulfilment-queue"],"role":"guarantee","source":"scenarios/progression-shipping-accounting.json","stablePackId":"ecommerce.inventory-operations"}],"id":"selected-source-096","scenario":{"level":3,"writeUrlPattern":null},"source":"scenarios/progression-shipping-accounting.json"},{"checkGroups":[{"checkGroupId":"signed-out-purchase","feature":{"actors":["visitor"],"criteria":[{"id":"3a","steps":[{"actor":"visitor","as":"keyboard-before-guest","do":"recordNumber","in":{"contains":"Keyboard","testid":"item-card"},"testid":"item-stock"},{"actor":"visitor","do":"click","ifAvailable":true,"in":{"contains":"Keyboard","testid":"item-card"},"settleMs":1500,"testid":"buy-now"},{"actor":"visitor","do":"reload","settleMs":2000},{"actor":"visitor","do":"click","ifAvailable":true,"testid":"overlay-close"},{"actor":"visitor","do":"click","ifAvailable":true,"testid":"catalog-link"},{"actor":"visitor","do":"expectNumber","in":{"contains":"Keyboard","testid":"item-card"},"plus":0,"relativeTo":"keyboard-before-guest","testid":"item-stock"}]}],"id":3,"setup":[{"actor":"visitor","contains":"Keyboard","do":"expect","testid":"item-card"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","requiresFeatures":["ecommerce.feature.purchasing"],"role":"guarantee","source":"scenarios/progression-signed-out-purchase.json"}],"id":"selected-source-097","scenario":{"level":1,"writeUrlPattern":null},"source":"scenarios/progression-signed-out-purchase.json"},{"checkGroups":[{"checkGroupId":"split-tender-refunds-751","feature":{"actors":["owner","staff"],"criteria":[{"id":"751a","steps":[{"actor":"staff","do":"click","in":{"contains":"Split refund 751","testid":"support-ticket"},"testid":"support-refund"},{"actor":"owner","do":"freshClient"},{"actor":"owner-fresh","do":"signIn","name":"credit-owner-751"},{"actor":"owner-fresh","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"owner-fresh","do":"click","testid":"orders-toggle"},{"actor":"owner-fresh","contains":"Desk Lamp","do":"expectElementCount","equals":1,"testid":"refund-entry","within":10000},{"actor":"owner-fresh","do":"expectNumber","equals":42,"in":{"contains":"Desk Lamp","testid":"order-item"},"testid":"order-refund-total"},{"actor":"owner-fresh","do":"expectNumber","equals":10,"in":{"contains":"Desk Lamp","testid":"refund-entry"},"testid":"refund-credit-amount"},{"actor":"owner-fresh","do":"expectNumber","equals":32,"in":{"contains":"Desk Lamp","testid":"refund-entry"},"testid":"refund-external-amount"},{"actor":"owner-fresh","do":"click","testid":"credit-link"},{"actor":"owner-fresh","attribute":"aria-busy","do":"expect","testid":"credit-panel","value":"false","within":10000},{"actor":"owner-fresh","do":"expectNumber","equals":10,"testid":"credit-balance"}]}],"id":751,"setup":[{"actor":"owner","do":"signUp","name":"credit-owner-751"},{"actor":"owner","do":"click","testid":"credit-link","unlessVisible":"credit-panel"},{"actor":"owner","attribute":"aria-busy","do":"expect","testid":"credit-panel","value":"false","within":10000},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"staff","do":"click","testid":"credit-link","unlessVisible":"credit-panel"},{"actor":"staff","attribute":"aria-busy","do":"expect","testid":"credit-panel","value":"false","within":10000},{"actor":"staff","do":"fill","testid":"credit-amount-input","text":"10.00"},{"actor":"staff","do":"fill","testid":"credit-reference-input","text":"credit-751"},{"action":"grantCredit","actor":"staff","do":"callAction","from":"staff","input":{"attribute":"data-action-input","overrides":{"accountId":{"actor":"owner","attribute":"data-account-id","testid":"credit-panel"}},"testid":"credit-grant"},"namedAction":{"args":[0,1000,""],"id":"grantCredit","method":"POST","params":[{"in":"body","name":"accountId","wireType":"u64"},{"in":"body","name":"amountMinor"},{"in":"body","name":"reference"}],"path":"/api/staff/credit","reducer":"grant_credit"},"settleMs":0},{"actor":"staff","do":"expectActionOutcome","outcome":"accepted"},{"actor":"owner","do":"reload","settleMs":1000},{"actor":"owner","do":"ensureSignedIn","name":"credit-owner-751","readyTestid":"current-user"},{"actor":"owner","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"owner","do":"click","testid":"credit-link","unlessVisible":"credit-balance"},{"actor":"owner","do":"expectNumber","equals":10,"testid":"credit-balance","within":10000},{"actor":"owner","do":"click","testid":"catalog-link"},{"actor":"owner","do":"click","in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"add-to-cart"},{"actor":"owner","do":"click","testid":"cart-toggle"},{"actor":"owner","do":"expectNumber","equals":42,"testid":"cart-total"},{"actor":"owner","do":"click","testid":"credit-checkout"},{"actor":"owner","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"owner","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"owner","do":"expectNumber","equals":10,"in":{"contains":"Desk Lamp","testid":"order-item"},"testid":"payment-credit-amount","within":10000},{"actor":"owner","do":"expectNumber","equals":32,"in":{"contains":"Desk Lamp","testid":"order-item"},"testid":"payment-external-amount"},{"actor":"owner","do":"click","testid":"support-link"},{"actor":"owner","do":"fill","testid":"support-subject","text":"Split refund 751"},{"actor":"owner","do":"fill","testid":"support-message","text":"Please refund this order."},{"actor":"owner","do":"click","testid":"support-submit"},{"actor":"owner","contains":"Desk Lamp","do":"click","in":{"contains":"Split refund 751","testid":"support-ticket"},"testid":"support-order-option"},{"actor":"owner","do":"click","in":{"contains":"Split refund 751","testid":"support-ticket"},"testid":"support-link-order"},{"actor":"staff","do":"click","testid":"staff-link","unlessVisible":"support-assignee"},{"actor":"staff","do":"click","ifAvailable":true,"testid":"support-queue-link","unlessVisible":"support-assignee","within":1000}]},"packId":"ecommerce.feature.split-tender-refunds","requiresFeatures":["ecommerce.feature.split-tender-refunds","ecommerce.feature.store-credit","ecommerce.progression.support-refunds"],"role":"feature","source":"scenarios/progression-split-tender-refunds.json"},{"checkGroupId":"production-756","feature":{"actors":["owner","staff","staff2"],"criteria":[{"id":"756a","steps":[{"action":"supportRefund","actors":["staff","staff2"],"do":"callConcurrently","from":"staff","input":{"attribute":"data-refund-input","contains":"Split refund 756","testid":"support-ticket"},"namedAction":{"args":[0],"id":"supportRefund","method":"POST","params":[{"in":"path","name":"caseId","placeholder":"{caseId}","wireType":"u64"}],"path":"/api/support/cases/{caseId}/refund","reducer":"support_refund"},"settleMs":0},{"do":"expectCallOutcomes"},{"actor":"owner","do":"freshClient"},{"actor":"owner-fresh","do":"signIn","name":"credit-owner-756"},{"actor":"owner-fresh","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"owner-fresh","do":"click","testid":"orders-toggle"},{"actor":"owner-fresh","contains":"Desk Lamp","do":"expectElementCount","equals":1,"testid":"refund-entry","within":10000},{"actor":"owner-fresh","do":"expectNumber","equals":42,"in":{"contains":"Desk Lamp","testid":"order-item"},"testid":"order-refund-total"},{"actor":"owner-fresh","do":"expectNumber","equals":10,"in":{"contains":"Desk Lamp","testid":"refund-entry"},"testid":"refund-credit-amount"},{"actor":"owner-fresh","do":"expectNumber","equals":32,"in":{"contains":"Desk Lamp","testid":"refund-entry"},"testid":"refund-external-amount"},{"actor":"owner-fresh","do":"click","testid":"credit-link"},{"actor":"owner-fresh","attribute":"aria-busy","do":"expect","testid":"credit-panel","value":"false","within":10000},{"actor":"owner-fresh","do":"expectNumber","equals":10,"testid":"credit-balance"},{"do":"restartBackend","settleMs":1000},{"actor":"owner","do":"freshClient"},{"actor":"owner-fresh","do":"signIn","name":"credit-owner-756"},{"actor":"owner-fresh","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"owner-fresh","do":"click","testid":"orders-toggle"},{"actor":"owner-fresh","contains":"Desk Lamp","do":"expectElementCount","equals":1,"testid":"refund-entry","within":10000},{"actor":"owner-fresh","do":"expectNumber","equals":42,"in":{"contains":"Desk Lamp","testid":"order-item"},"testid":"order-refund-total"},{"actor":"owner-fresh","do":"expectNumber","equals":10,"in":{"contains":"Desk Lamp","testid":"refund-entry"},"testid":"refund-credit-amount"},{"actor":"owner-fresh","do":"expectNumber","equals":32,"in":{"contains":"Desk Lamp","testid":"refund-entry"},"testid":"refund-external-amount"},{"actor":"owner-fresh","do":"click","testid":"credit-link"},{"actor":"owner-fresh","attribute":"aria-busy","do":"expect","testid":"credit-panel","value":"false","within":10000},{"actor":"owner-fresh","do":"expectNumber","equals":10,"testid":"credit-balance"}]}],"id":756,"setup":[{"actor":"owner","do":"signUp","name":"credit-owner-756"},{"actor":"owner","do":"click","testid":"credit-link","unlessVisible":"credit-panel"},{"actor":"owner","attribute":"aria-busy","do":"expect","testid":"credit-panel","value":"false","within":10000},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"staff","do":"click","testid":"credit-link","unlessVisible":"credit-panel"},{"actor":"staff","attribute":"aria-busy","do":"expect","testid":"credit-panel","value":"false","within":10000},{"actor":"staff","do":"fill","testid":"credit-amount-input","text":"10.00"},{"actor":"staff","do":"fill","testid":"credit-reference-input","text":"credit-756"},{"action":"grantCredit","actor":"staff","do":"callAction","from":"staff","input":{"attribute":"data-action-input","overrides":{"accountId":{"actor":"owner","attribute":"data-account-id","testid":"credit-panel"}},"testid":"credit-grant"},"namedAction":{"args":[0,1000,""],"id":"grantCredit","method":"POST","params":[{"in":"body","name":"accountId","wireType":"u64"},{"in":"body","name":"amountMinor"},{"in":"body","name":"reference"}],"path":"/api/staff/credit","reducer":"grant_credit"},"settleMs":0},{"actor":"staff","do":"expectActionOutcome","outcome":"accepted"},{"actor":"owner","do":"reload","settleMs":1000},{"actor":"owner","do":"ensureSignedIn","name":"credit-owner-756","readyTestid":"current-user"},{"actor":"owner","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"owner","do":"click","testid":"credit-link","unlessVisible":"credit-balance"},{"actor":"owner","do":"expectNumber","equals":10,"testid":"credit-balance","within":10000},{"actor":"owner","do":"click","testid":"catalog-link"},{"actor":"owner","do":"click","in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"add-to-cart"},{"actor":"owner","do":"click","testid":"cart-toggle"},{"actor":"owner","do":"expectNumber","equals":42,"testid":"cart-total"},{"actor":"owner","do":"click","testid":"credit-checkout"},{"actor":"owner","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"owner","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"owner","do":"expectNumber","equals":10,"in":{"contains":"Desk Lamp","testid":"order-item"},"testid":"payment-credit-amount","within":10000},{"actor":"owner","do":"expectNumber","equals":32,"in":{"contains":"Desk Lamp","testid":"order-item"},"testid":"payment-external-amount"},{"actor":"owner","do":"click","testid":"support-link"},{"actor":"owner","do":"fill","testid":"support-subject","text":"Split refund 756"},{"actor":"owner","do":"fill","testid":"support-message","text":"Please refund this order."},{"actor":"owner","do":"click","testid":"support-submit"},{"actor":"owner","contains":"Desk Lamp","do":"click","in":{"contains":"Split refund 756","testid":"support-ticket"},"testid":"support-order-option"},{"actor":"owner","do":"click","in":{"contains":"Split refund 756","testid":"support-ticket"},"testid":"support-link-order"},{"actor":"staff","do":"click","testid":"staff-link","unlessVisible":"support-assignee"},{"actor":"staff","do":"click","ifAvailable":true,"testid":"support-queue-link","unlessVisible":"support-assignee","within":1000},{"actor":"staff2","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.split-tender-refunds","requiresFeatures":["ecommerce.feature.split-tender-refunds","ecommerce.feature.store-credit","ecommerce.progression.support-refunds"],"role":"guarantee","source":"scenarios/progression-split-tender-refunds.json"}],"id":"selected-source-098","scenario":{"level":6,"writeUrlPattern":null},"source":"scenarios/progression-split-tender-refunds.json"},{"checkGroups":[{"checkGroupId":"staff-access","feature":{"actors":["customer","staff","admin","authorized"],"criteria":[{"id":"601a","steps":[{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"staff","do":"click","testid":"staff-link"},{"actor":"staff","do":"expect","testid":"staff-area","within":6000},{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"click","testid":"staff-link"},{"actor":"admin","do":"expect","testid":"staff-area","within":6000}]}],"id":601,"setup":[]},"packId":"ecommerce.progression.staff-access","role":"feature","source":"scenarios/progression-staff-access.json"},{"checkGroupId":"staff-area-boundary","feature":{"actors":["customer","staff","admin","authorized"],"criteria":[{"id":"601b","steps":[{"actor":"authorized","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"authorized","do":"click","testid":"staff-link"},{"actor":"authorized","do":"expect","testid":"staff-area"},{"actor":"customer","do":"signIn","exact":true,"name":"customer","password":"stackbench-customer-2026"},{"actor":"customer","do":"click","ifAvailable":true,"settleMs":1500,"testid":"staff-link"},{"absent":true,"actor":"customer","do":"expect","testid":"staff-area"}]}],"id":601,"setup":[]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","requiresFeatures":["ecommerce.progression.staff-access"],"role":"guarantee","source":"scenarios/progression-staff-access.json"}],"id":"selected-source-099","scenario":{"level":1,"writeUrlPattern":null},"source":"scenarios/progression-staff-access.json"},{"checkGroups":[{"checkGroupId":"staff-activity","feature":{"actors":["admin","staff","customer"],"criteria":[{"id":"624a","steps":[{"actor":"staff","do":"click","testid":"staff-link"},{"actor":"staff","do":"click","testid":"activity-link"},{"actor":"staff","contains":"Activity Mug","do":"expect","testid":"activity-entry","within":10000},{"actor":"staff","contains":"admin","do":"expect","in":{"contains":"Activity Mug","testid":"activity-entry"},"testid":"activity-actor"},{"actor":"staff","contains":"creat","do":"expect","in":{"contains":"Activity Mug","testid":"activity-entry"},"testid":"activity-action"},{"actor":"staff","contains":"Activity Mug","do":"expect","in":{"contains":"Activity Mug","testid":"activity-entry"},"testid":"activity-subject"},{"actor":"staff","do":"expect","in":{"contains":"Activity Mug","testid":"activity-entry"},"testid":"activity-time"}]}],"id":624,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"customer","do":"signIn","exact":true,"name":"customer","password":"stackbench-customer-2026"},{"actor":"admin","do":"click","testid":"admin-link"},{"actor":"admin","do":"fill","testid":"catalog-name","text":"Activity Mug"},{"actor":"admin","do":"fill","testid":"catalog-category","text":"Kitchen"},{"actor":"admin","do":"fill","testid":"catalog-price","text":"43.00"},{"actor":"admin","do":"fill","testid":"catalog-variants","text":"Green"},{"actor":"admin","do":"click","testid":"catalog-save"}]},"packId":"ecommerce.progression.staff-activity","role":"feature","source":"scenarios/progression-staff-activity.json"},{"checkGroupId":"staff-activity-privacy","feature":{"actors":["admin","staff","customer"],"criteria":[{"id":"624b","steps":[{"absent":true,"actor":"customer","do":"expect","testid":"activity-link"}]}],"id":624,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"customer","do":"signIn","exact":true,"name":"customer","password":"stackbench-customer-2026"},{"actor":"admin","do":"click","testid":"admin-link"},{"actor":"admin","do":"fill","testid":"catalog-name","text":"Activity Mug"},{"actor":"admin","do":"fill","testid":"catalog-category","text":"Kitchen"},{"actor":"admin","do":"fill","testid":"catalog-price","text":"43.00"},{"actor":"admin","do":"fill","testid":"catalog-variants","text":"Green"},{"actor":"admin","do":"click","testid":"catalog-save"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","requiresFeatures":["ecommerce.progression.staff-activity"],"role":"guarantee","source":"scenarios/progression-staff-activity.json"}],"id":"selected-source-100","scenario":{"level":5,"writeUrlPattern":null},"source":"scenarios/progression-staff-activity.json"},{"checkGroups":[{"checkGroupId":"staff-roles","feature":{"actors":["admin","replayAdmin","staff","roleAdmin","promotedStaff"],"criteria":[{"id":"621c","steps":[{"actor":"admin","do":"expect","in":{"testid":"staff-role-account-staff"},"testid":"staff-role-select","value":"inventory","within":10000}]}],"id":621,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"expect","testid":"admin-link","within":6000},{"actor":"admin","do":"click","testid":"admin-link","unlessVisible":"staff-role-account-staff"},{"actor":"admin","do":"fill","in":{"testid":"staff-role-account-staff"},"testid":"staff-role-select","text":"inventory"},{"actor":"admin","do":"click","in":{"testid":"staff-role-account-staff"},"testid":"staff-role-save"}]},"packId":"ecommerce.progression.staff-roles","role":"feature","source":"scenarios/progression-staff-roles.json"},{"checkGroupId":"staff-role-reload","feature":{"actors":["admin","replayAdmin","staff","roleAdmin","promotedStaff"],"criteria":[{"id":"621a","steps":[{"actor":"admin","do":"reload","settleMs":2500},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"admin-link","unlessVisible":"staff-role-account-staff"},{"actor":"admin","do":"expect","in":{"testid":"staff-role-account-staff"},"testid":"staff-role-select","value":"inventory","within":10000},{"do":"restartBackend","settleMs":1000},{"actor":"admin","do":"freshClient"},{"actor":"admin-fresh","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin-fresh","do":"click","testid":"admin-link","unlessVisible":"staff-role-account-staff"},{"actor":"admin-fresh","do":"expect","in":{"testid":"staff-role-account-staff"},"testid":"staff-role-select","value":"inventory","within":10000}]}],"id":621,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"expect","testid":"admin-link","within":6000},{"actor":"admin","do":"click","testid":"admin-link","unlessVisible":"staff-role-account-staff"},{"actor":"admin","do":"fill","in":{"testid":"staff-role-account-staff"},"testid":"staff-role-select","text":"inventory"},{"actor":"admin","do":"click","in":{"testid":"staff-role-account-staff"},"testid":"staff-role-save"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.state-durability","requiresFeatures":["ecommerce.progression.staff-roles"],"role":"guarantee","source":"scenarios/progression-staff-roles.json"},{"checkGroupId":"staff-role-boundary","feature":{"actors":["admin","replayAdmin","staff","roleAdmin","promotedStaff"],"criteria":[{"id":"621b","steps":[{"actor":"replayAdmin","do":"reload","settleMs":0},{"actor":"replayAdmin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"replayAdmin","do":"expect","testid":"admin-link","within":6000},{"actor":"replayAdmin","do":"click","testid":"admin-link","unlessVisible":"staff-role-account-staff"},{"actor":"replayAdmin","do":"fill","in":{"testid":"staff-role-account-staff"},"testid":"staff-role-select","text":"staff"},{"actor":"replayAdmin","do":"click","in":{"testid":"staff-role-account-staff"},"testid":"staff-role-save"},{"actor":"replayAdmin","do":"reload","settleMs":1000},{"actor":"replayAdmin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"replayAdmin","do":"click","ifAvailable":true,"testid":"admin-link","unlessVisible":"staff-role-account-staff"},{"actor":"replayAdmin","do":"expect","in":{"testid":"staff-role-account-staff"},"testid":"staff-role-select","value":"staff","within":10000},{"actor":"staff","do":"reload","settleMs":0},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"staff","do":"click","ifAvailable":true,"testid":"staff-link"},{"absent":true,"actor":"staff","do":"expect","testid":"staff-role-save"},{"actor":"staff","do":"replayAs","from":"replayAdmin","match":"role","namedAction":{"args":[0,"inventory"],"id":"assignStaffRole","method":"PUT","params":[{"in":"path","name":"accountId","placeholder":":id","wireType":"u64"},{"in":"body","name":"role"}],"path":"/api/staff/:id/role","reducer":"assign_staff_role"},"namedTarget":{"attribute":"data-account-id","testid":"staff-role-account-staff","valueType":"string"},"settleMs":1500,"swap":{"find":"\"role\":\"staff\"","with":"\"role\":\"inventory\""}},{"actor":"staff","do":"expectReplayRejected"},{"actor":"replayAdmin","do":"reload","settleMs":1000},{"actor":"replayAdmin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"replayAdmin","do":"click","ifAvailable":true,"testid":"admin-link","unlessVisible":"staff-role-account-staff"},{"actor":"replayAdmin","do":"expect","in":{"testid":"staff-role-account-staff"},"testid":"staff-role-select","value":"staff","within":10000}]}],"id":621,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"expect","testid":"admin-link","within":6000},{"actor":"admin","do":"click","testid":"admin-link","unlessVisible":"staff-role-account-staff"},{"actor":"admin","do":"fill","in":{"testid":"staff-role-account-staff"},"testid":"staff-role-select","text":"inventory"},{"actor":"admin","do":"click","in":{"testid":"staff-role-account-staff"},"testid":"staff-role-save"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","requiresFeatures":["ecommerce.progression.staff-roles"],"role":"guarantee","source":"scenarios/progression-staff-roles.json"},{"checkGroupId":"staff-role-revocation","feature":{"actors":["admin","replayAdmin","staff","roleAdmin","promotedStaff"],"criteria":[{"id":"621d","steps":[{"actor":"roleAdmin","do":"reload","settleMs":0},{"actor":"roleAdmin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"roleAdmin","do":"click","testid":"admin-link","unlessVisible":"staff-role-account-staff"},{"actor":"roleAdmin","do":"replayAs","from":"roleAdmin","match":"__role-revocation-named-action__","namedAction":{"args":[0,"admin"],"id":"assignStaffRole","method":"PUT","params":[{"in":"path","name":"accountId","placeholder":":id","wireType":"u64"},{"in":"body","name":"role"}],"path":"/api/staff/:id/role","reducer":"assign_staff_role"},"namedTarget":{"attribute":"data-account-id","testid":"staff-role-account-staff","valueType":"string"},"settleMs":0},{"actor":"roleAdmin","do":"expectReplayCompleted","requireAccepted":true},{"actor":"roleAdmin","do":"reload","settleMs":0},{"actor":"roleAdmin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"roleAdmin","do":"click","ifAvailable":true,"testid":"admin-link","unlessVisible":"staff-role-account-staff"},{"actor":"roleAdmin","do":"expect","in":{"testid":"staff-role-account-staff"},"testid":"staff-role-select","value":"admin","within":10000},{"actor":"promotedStaff","do":"reload","settleMs":0},{"actor":"promotedStaff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"promotedStaff","do":"replayAs","from":"roleAdmin","match":"__role-revocation-named-action__","namedAction":{"args":[0,"admin"],"id":"assignStaffRole","method":"PUT","params":[{"in":"path","name":"accountId","placeholder":":id","wireType":"u64"},{"in":"body","name":"role"}],"path":"/api/staff/:id/role","reducer":"assign_staff_role"},"namedTarget":{"attribute":"data-account-id","testid":"staff-role-account-staff","valueType":"string"},"settleMs":0},{"actor":"promotedStaff","do":"expectReplayCompleted","requireAccepted":true},{"actor":"roleAdmin","do":"replayAs","from":"roleAdmin","match":"__role-revocation-named-action__","namedAction":{"args":[0,"staff"],"id":"assignStaffRole","method":"PUT","params":[{"in":"path","name":"accountId","placeholder":":id","wireType":"u64"},{"in":"body","name":"role"}],"path":"/api/staff/:id/role","reducer":"assign_staff_role"},"namedTarget":{"attribute":"data-account-id","testid":"staff-role-account-staff","valueType":"string"},"settleMs":0},{"actor":"roleAdmin","do":"expectReplayCompleted","requireAccepted":true},{"actor":"roleAdmin","do":"reload","settleMs":0},{"actor":"roleAdmin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"roleAdmin","do":"click","ifAvailable":true,"testid":"admin-link","unlessVisible":"staff-role-account-staff"},{"actor":"roleAdmin","do":"expect","in":{"testid":"staff-role-account-staff"},"testid":"staff-role-select","value":"staff","within":10000},{"actor":"promotedStaff","do":"replayAs","from":"roleAdmin","match":"__role-revocation-named-action__","namedAction":{"args":[0,"admin"],"id":"assignStaffRole","method":"PUT","params":[{"in":"path","name":"accountId","placeholder":":id","wireType":"u64"},{"in":"body","name":"role"}],"path":"/api/staff/:id/role","reducer":"assign_staff_role"},"namedTarget":{"attribute":"data-account-id","testid":"staff-role-account-staff","valueType":"string"},"settleMs":0},{"actor":"promotedStaff","do":"expectReplayRejected"},{"actor":"roleAdmin","do":"reload","settleMs":0},{"actor":"roleAdmin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"roleAdmin","do":"click","ifAvailable":true,"testid":"admin-link","unlessVisible":"staff-role-account-staff"},{"actor":"roleAdmin","do":"expect","in":{"testid":"staff-role-account-staff"},"testid":"staff-role-select","value":"staff","within":10000}]}],"id":621,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"expect","testid":"admin-link","within":6000},{"actor":"admin","do":"click","testid":"admin-link","unlessVisible":"staff-role-account-staff"},{"actor":"admin","do":"fill","in":{"testid":"staff-role-account-staff"},"testid":"staff-role-select","text":"inventory"},{"actor":"admin","do":"click","in":{"testid":"staff-role-account-staff"},"testid":"staff-role-save"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","requiresFeatures":["ecommerce.progression.staff-roles"],"role":"guarantee","source":"scenarios/progression-staff-roles.json"}],"id":"selected-source-101","scenario":{"level":2,"writeUrlPattern":null},"source":"scenarios/progression-staff-roles.json"},{"checkGroups":[{"checkGroupId":"stock-alert-delivery","feature":{"actors":["subscriber","admin"],"criteria":[{"id":"631c","steps":[{"actor":"subscriber","do":"freshClient"},{"actor":"subscriber-fresh","do":"signIn","name":"stock-subscriber"},{"actor":"subscriber-fresh","do":"click","testid":"notifications-toggle","unlessVisible":"notifications-panel"},{"actor":"subscriber-fresh","attribute":"aria-busy","do":"expect","testid":"notifications-panel","value":"false","within":10000},{"actor":"subscriber-fresh","contains":"Air Purifier","do":"expectElementCount","equals":0,"testid":"stock-alert-delivery"},{"actor":"admin","do":"click","testid":"admin-link"},{"action":"restock","actor":"admin","do":"callAction","input":{"attribute":"data-restock-input","contains":"Air Purifier","testid":"admin-location-row"},"namedAction":{"args":[0,0,1],"id":"restock","params":[{"in":"body","name":"itemId","wireType":"u64"},{"in":"body","name":"warehouseId","wireType":"u64"},{"in":"body","name":"quantity"}],"path":"/api/admin/restock","reducer":"admin_restock"},"settleMs":0},{"actor":"admin","do":"expectActionOutcome","outcome":"accepted"},{"actor":"admin","do":"wait","ms":10000},{"actor":"subscriber","do":"freshClient"},{"actor":"subscriber-fresh","do":"signIn","name":"stock-subscriber"},{"actor":"subscriber-fresh","do":"click","testid":"notifications-toggle","unlessVisible":"notifications-panel"},{"actor":"subscriber-fresh","attribute":"aria-busy","do":"expect","testid":"notifications-panel","value":"false","within":10000},{"actor":"subscriber-fresh","contains":"Air Purifier","do":"expect","testid":"stock-alert-delivery","within":10000}]}],"id":631,"setup":[{"actor":"subscriber","do":"signUp","name":"stock-subscriber"},{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"dbSetStock","item":"Air Purifier","quantity":0,"settleMs":1000,"warehouse":"East"},{"do":"dbSetStock","item":"Air Purifier","quantity":0,"settleMs":1000,"warehouse":"West"},{"actor":"subscriber","do":"reload","settleMs":1000},{"actor":"subscriber","do":"ensureSignedIn","name":"stock-subscriber","readyTestid":"current-user"},{"actor":"subscriber","do":"click","in":{"contains":"Air Purifier","testid":"item-card"},"testid":"stock-alert"},{"actor":"subscriber","attribute":"data-submit-state","contains":"Air Purifier","do":"expect","testid":"item-card","value":"succeeded","within":10000}]},"packId":"ecommerce.progression.stock-alerts","requiresFeatures":["ecommerce.feature.warehouse-admin"],"role":"feature","source":"scenarios/progression-stock-alert-delivery.json"}],"id":"selected-source-102","scenario":{"level":5,"writeUrlPattern":null},"source":"scenarios/progression-stock-alert-delivery.json"},{"checkGroups":[{"checkGroupId":"stock-alert-deduplication","feature":{"actors":["subscriber","other","admin"],"criteria":[{"id":"631a","steps":[{"actor":"subscriber","do":"freshClient"},{"actor":"subscriber-fresh","do":"signIn","name":"stock-subscriber"},{"actor":"subscriber-fresh","do":"click","testid":"notifications-toggle","unlessVisible":"notifications-panel"},{"actor":"subscriber-fresh","attribute":"aria-busy","do":"expect","testid":"notifications-panel","value":"false","within":10000},{"actor":"subscriber-fresh","contains":"Air Purifier","do":"expectElementCount","equals":1,"testid":"stock-alert-delivery","within":10000},{"action":"restock","actor":"admin","do":"callAction","input":{"attribute":"data-restock-input","contains":"Air Purifier","testid":"admin-location-row"},"namedAction":{"args":[0,0,1],"id":"restock","params":[{"in":"body","name":"itemId","wireType":"u64"},{"in":"body","name":"warehouseId","wireType":"u64"},{"in":"body","name":"quantity"}],"path":"/api/admin/restock","reducer":"admin_restock"},"settleMs":0},{"actor":"admin","do":"expectActionOutcome","outcome":"accepted"},{"actor":"admin","do":"wait","ms":10000},{"actor":"subscriber","do":"freshClient"},{"actor":"subscriber-fresh","do":"signIn","name":"stock-subscriber"},{"actor":"subscriber-fresh","do":"click","testid":"notifications-toggle","unlessVisible":"notifications-panel"},{"actor":"subscriber-fresh","attribute":"aria-busy","do":"expect","testid":"notifications-panel","value":"false","within":10000},{"actor":"subscriber-fresh","contains":"Air Purifier","do":"expectElementCount","equals":1,"testid":"stock-alert-delivery","within":10000}]}],"id":631,"setup":[{"actor":"subscriber","do":"signUp","name":"stock-subscriber"},{"actor":"other","do":"signUp","name":"stock-other"},{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"dbSetStock","item":"Air Purifier","quantity":0,"settleMs":1000,"warehouse":"East"},{"do":"dbSetStock","item":"Air Purifier","quantity":0,"settleMs":1000,"warehouse":"West"},{"actor":"subscriber","do":"reload","settleMs":1000},{"actor":"subscriber","do":"ensureSignedIn","name":"stock-subscriber","readyTestid":"current-user"},{"actor":"subscriber","do":"click","in":{"contains":"Air Purifier","testid":"item-card"},"testid":"stock-alert"},{"actor":"subscriber","attribute":"data-submit-state","contains":"Air Purifier","do":"expect","testid":"item-card","value":"succeeded","within":10000},{"actor":"admin","do":"click","testid":"admin-link"},{"action":"restock","actor":"admin","do":"callAction","input":{"attribute":"data-restock-input","contains":"Air Purifier","testid":"admin-location-row"},"namedAction":{"args":[0,0,1],"id":"restock","params":[{"in":"body","name":"itemId","wireType":"u64"},{"in":"body","name":"warehouseId","wireType":"u64"},{"in":"body","name":"quantity"}],"path":"/api/admin/restock","reducer":"admin_restock"},"settleMs":0},{"actor":"admin","do":"expectActionOutcome","outcome":"accepted"},{"actor":"admin","do":"wait","ms":10000}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.transactional-integrity","requiresFeatures":["ecommerce.feature.warehouse-admin","ecommerce.progression.stock-alerts"],"role":"guarantee","source":"scenarios/progression-stock-alerts.json"},{"checkGroupId":"stock-alert-privacy","feature":{"actors":["subscriber","other","admin"],"criteria":[{"id":"631b","steps":[{"actor":"subscriber","do":"freshClient"},{"actor":"subscriber-fresh","do":"signIn","name":"stock-subscriber"},{"actor":"subscriber-fresh","do":"click","testid":"notifications-toggle","unlessVisible":"notifications-panel"},{"actor":"subscriber-fresh","attribute":"aria-busy","do":"expect","testid":"notifications-panel","value":"false","within":10000},{"actor":"subscriber-fresh","contains":"Air Purifier","do":"expect","testid":"stock-alert-delivery","within":10000},{"actor":"other","do":"freshClient"},{"actor":"other-fresh","do":"signIn","name":"stock-other"},{"actor":"other-fresh","do":"click","testid":"notifications-toggle","unlessVisible":"notifications-panel"},{"actor":"other-fresh","attribute":"aria-busy","do":"expect","testid":"notifications-panel","value":"false","within":10000},{"absent":true,"actor":"other-fresh","contains":"Air Purifier","do":"expect","testid":"notification-item"}]}],"id":631,"setup":[{"actor":"subscriber","do":"signUp","name":"stock-subscriber"},{"actor":"other","do":"signUp","name":"stock-other"},{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"dbSetStock","item":"Air Purifier","quantity":0,"settleMs":1000,"warehouse":"East"},{"do":"dbSetStock","item":"Air Purifier","quantity":0,"settleMs":1000,"warehouse":"West"},{"actor":"subscriber","do":"reload","settleMs":1000},{"actor":"subscriber","do":"ensureSignedIn","name":"stock-subscriber","readyTestid":"current-user"},{"actor":"subscriber","do":"click","in":{"contains":"Air Purifier","testid":"item-card"},"testid":"stock-alert"},{"actor":"subscriber","attribute":"data-submit-state","contains":"Air Purifier","do":"expect","testid":"item-card","value":"succeeded","within":10000},{"actor":"admin","do":"click","testid":"admin-link"},{"action":"restock","actor":"admin","do":"callAction","input":{"attribute":"data-restock-input","contains":"Air Purifier","testid":"admin-location-row"},"namedAction":{"args":[0,0,1],"id":"restock","params":[{"in":"body","name":"itemId","wireType":"u64"},{"in":"body","name":"warehouseId","wireType":"u64"},{"in":"body","name":"quantity"}],"path":"/api/admin/restock","reducer":"admin_restock"},"settleMs":0},{"actor":"admin","do":"expectActionOutcome","outcome":"accepted"},{"actor":"admin","do":"wait","ms":10000}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","requiresFeatures":["ecommerce.feature.warehouse-admin","ecommerce.progression.stock-alerts"],"role":"guarantee","source":"scenarios/progression-stock-alerts.json"}],"id":"selected-source-103","scenario":{"level":5,"writeUrlPattern":null},"source":"scenarios/progression-stock-alerts.json"},{"checkGroups":[{"checkGroupId":"stock-limit","feature":{"actors":["buyer","watcher","visitor"],"criteria":[{"id":"3d","steps":[{"actor":"buyer","do":"click","in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"buy-now"},{"actor":"buyer","do":"wait","ms":800},{"actor":"buyer","do":"click","in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"buy-now"},{"actor":"buyer","do":"wait","ms":800},{"actor":"buyer","do":"click","in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"buy-now"},{"actor":"buyer","do":"expectNumber","equals":0,"in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"item-stock"},{"actor":"buyer","do":"expect","in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"out-of-stock"},{"action":"buy","actor":"buyer","do":"callAction","input":{"attribute":"data-buy-input","contains":"Desk Lamp","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"},"settleMs":2000},{"actor":"buyer","do":"expectActionOutcome","outcome":"validation-refused"},{"actor":"buyer","do":"reload","settleMs":3000},{"actor":"buyer","do":"ensureSignedIn","name":"eli","readyTestid":"current-user"},{"actor":"buyer","do":"expectNumber","equals":0,"in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"item-stock"}]}],"id":3,"setup":[{"do":"dbSetStock","item":"Desk Lamp","quantity":2,"settleMs":2000,"warehouse":"East"},{"do":"dbSetStock","item":"Desk Lamp","quantity":1,"settleMs":2000,"warehouse":"West"},{"actor":"buyer","do":"signUp","name":"eli"},{"actor":"watcher","do":"signUp","name":"fay"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.concurrency-safety","requiresFeatures":["ecommerce.feature.purchasing"],"role":"guarantee","source":"scenarios/progression-stock-limit.json"}],"id":"selected-source-104","scenario":{"level":1,"writeUrlPattern":null},"source":"scenarios/progression-stock-limit.json"},{"checkGroups":[{"checkGroupId":"store-credit-750","feature":{"actors":["owner","staff","tab"],"criteria":[{"id":"750a","steps":[{"actor":"owner","do":"click","testid":"credit-checkout"},{"actor":"owner","do":"freshClient"},{"actor":"owner-fresh","do":"signIn","name":"credit-owner-750"},{"actor":"owner-fresh","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"owner-fresh","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"owner-fresh","contains":"Desk Lamp","do":"expectElementCount","equals":1,"testid":"order-item","within":10000},{"actor":"owner-fresh","do":"expectNumber","equals":10,"in":{"contains":"Desk Lamp","testid":"order-item"},"testid":"payment-credit-amount"},{"actor":"owner-fresh","do":"expectNumber","equals":32,"in":{"contains":"Desk Lamp","testid":"order-item"},"testid":"payment-external-amount"},{"actor":"owner-fresh","do":"expectNumber","equals":42,"in":{"contains":"Desk Lamp","testid":"order-item"},"testid":"payment-amount"},{"actor":"owner-fresh","do":"click","testid":"credit-link","unlessVisible":"credit-panel"},{"actor":"owner-fresh","attribute":"aria-busy","do":"expect","testid":"credit-panel","value":"false","within":10000},{"actor":"owner-fresh","do":"expectNumber","equals":0,"testid":"credit-balance"}]}],"id":750,"setup":[{"actor":"owner","do":"signUp","name":"credit-owner-750"},{"actor":"owner","do":"click","testid":"credit-link","unlessVisible":"credit-panel"},{"actor":"owner","attribute":"aria-busy","do":"expect","testid":"credit-panel","value":"false","within":10000},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"staff","do":"click","testid":"credit-link","unlessVisible":"credit-panel"},{"actor":"staff","attribute":"aria-busy","do":"expect","testid":"credit-panel","value":"false","within":10000},{"actor":"staff","do":"fill","testid":"credit-amount-input","text":"10.00"},{"actor":"staff","do":"fill","testid":"credit-reference-input","text":"credit-750"},{"action":"grantCredit","actor":"staff","do":"callAction","from":"staff","input":{"attribute":"data-action-input","overrides":{"accountId":{"actor":"owner","attribute":"data-account-id","testid":"credit-panel"}},"testid":"credit-grant"},"namedAction":{"args":[0,1000,""],"id":"grantCredit","method":"POST","params":[{"in":"body","name":"accountId","wireType":"u64"},{"in":"body","name":"amountMinor"},{"in":"body","name":"reference"}],"path":"/api/staff/credit","reducer":"grant_credit"},"settleMs":0},{"actor":"staff","do":"expectActionOutcome","outcome":"accepted"},{"actor":"owner","do":"reload","settleMs":1000},{"actor":"owner","do":"ensureSignedIn","name":"credit-owner-750","readyTestid":"current-user"},{"actor":"owner","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"owner","do":"click","testid":"credit-link","unlessVisible":"credit-balance"},{"actor":"owner","do":"expectNumber","equals":10,"testid":"credit-balance","within":10000},{"actor":"owner","do":"click","testid":"catalog-link"},{"actor":"owner","do":"click","in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"add-to-cart"},{"actor":"owner","do":"click","testid":"cart-toggle"},{"actor":"owner","do":"expectNumber","equals":42,"testid":"cart-total"}]},"packId":"ecommerce.feature.store-credit","role":"feature","source":"scenarios/progression-store-credit.json"},{"checkGroupId":"production-752","feature":{"actors":["owner","staff","tab"],"criteria":[{"id":"752a","steps":[{"action":"grantCredit","actor":"staff","do":"callAction","from":"staff","input":{"attribute":"data-action-input","overrides":{"accountId":{"actor":"owner","attribute":"data-account-id","testid":"credit-panel"}},"testid":"credit-grant"},"namedAction":{"args":[0,1000,""],"id":"grantCredit","method":"POST","params":[{"in":"body","name":"accountId","wireType":"u64"},{"in":"body","name":"amountMinor"},{"in":"body","name":"reference"}],"path":"/api/staff/credit","reducer":"grant_credit"},"settleMs":0},{"actor":"staff","do":"expectActionOutcome","outcome":"completed"},{"actor":"owner","do":"freshClient"},{"actor":"owner-fresh","do":"signIn","name":"credit-owner-752"},{"actor":"owner-fresh","do":"click","testid":"credit-link","unlessVisible":"credit-panel"},{"actor":"owner-fresh","attribute":"aria-busy","do":"expect","testid":"credit-panel","value":"false","within":10000},{"actor":"owner-fresh","do":"expectNumber","equals":10,"testid":"credit-balance"}]}],"id":752,"setup":[{"actor":"owner","do":"signUp","name":"credit-owner-752"},{"actor":"owner","do":"click","testid":"credit-link","unlessVisible":"credit-panel"},{"actor":"owner","attribute":"aria-busy","do":"expect","testid":"credit-panel","value":"false","within":10000},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"staff","do":"click","testid":"credit-link","unlessVisible":"credit-panel"},{"actor":"staff","attribute":"aria-busy","do":"expect","testid":"credit-panel","value":"false","within":10000},{"actor":"staff","do":"fill","testid":"credit-amount-input","text":"10.00"},{"actor":"staff","do":"fill","testid":"credit-reference-input","text":"credit-752"},{"action":"grantCredit","actor":"staff","do":"callAction","from":"staff","input":{"attribute":"data-action-input","overrides":{"accountId":{"actor":"owner","attribute":"data-account-id","testid":"credit-panel"}},"testid":"credit-grant"},"namedAction":{"args":[0,1000,""],"id":"grantCredit","method":"POST","params":[{"in":"body","name":"accountId","wireType":"u64"},{"in":"body","name":"amountMinor"},{"in":"body","name":"reference"}],"path":"/api/staff/credit","reducer":"grant_credit"},"settleMs":0},{"actor":"staff","do":"expectActionOutcome","outcome":"accepted"},{"actor":"owner","do":"reload","settleMs":1000},{"actor":"owner","do":"ensureSignedIn","name":"credit-owner-752","readyTestid":"current-user"},{"actor":"owner","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"owner","do":"click","testid":"credit-link","unlessVisible":"credit-balance"},{"actor":"owner","do":"expectNumber","equals":10,"testid":"credit-balance","within":10000}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.store-credit","requiresFeatures":["ecommerce.feature.store-credit"],"role":"guarantee","source":"scenarios/progression-store-credit.json"},{"checkGroupId":"production-753","feature":{"actors":["owner","staff","tab"],"criteria":[{"id":"753a","steps":[{"actor":"staff","do":"fill","testid":"credit-reference-input","text":"unauthorized-credit-753"},{"action":"grantCredit","actor":"owner","do":"callAction","from":"staff","input":{"attribute":"data-action-input","overrides":{"accountId":{"actor":"owner","attribute":"data-account-id","testid":"credit-panel"}},"testid":"credit-grant"},"namedAction":{"args":[0,1000,""],"id":"grantCredit","method":"POST","params":[{"in":"body","name":"accountId","wireType":"u64"},{"in":"body","name":"amountMinor"},{"in":"body","name":"reference"}],"path":"/api/staff/credit","reducer":"grant_credit"},"settleMs":0},{"actor":"owner","do":"expectActionOutcome","outcome":"refused"},{"actor":"owner","do":"freshClient"},{"actor":"owner-fresh","do":"signIn","name":"credit-owner-753"},{"actor":"owner-fresh","do":"click","testid":"credit-link","unlessVisible":"credit-panel"},{"actor":"owner-fresh","attribute":"aria-busy","do":"expect","testid":"credit-panel","value":"false","within":10000},{"actor":"owner-fresh","do":"expectNumber","equals":10,"testid":"credit-balance"}]}],"id":753,"setup":[{"actor":"owner","do":"signUp","name":"credit-owner-753"},{"actor":"owner","do":"click","testid":"credit-link","unlessVisible":"credit-panel"},{"actor":"owner","attribute":"aria-busy","do":"expect","testid":"credit-panel","value":"false","within":10000},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"staff","do":"click","testid":"credit-link","unlessVisible":"credit-panel"},{"actor":"staff","attribute":"aria-busy","do":"expect","testid":"credit-panel","value":"false","within":10000},{"actor":"staff","do":"fill","testid":"credit-amount-input","text":"10.00"},{"actor":"staff","do":"fill","testid":"credit-reference-input","text":"credit-753"},{"action":"grantCredit","actor":"staff","do":"callAction","from":"staff","input":{"attribute":"data-action-input","overrides":{"accountId":{"actor":"owner","attribute":"data-account-id","testid":"credit-panel"}},"testid":"credit-grant"},"namedAction":{"args":[0,1000,""],"id":"grantCredit","method":"POST","params":[{"in":"body","name":"accountId","wireType":"u64"},{"in":"body","name":"amountMinor"},{"in":"body","name":"reference"}],"path":"/api/staff/credit","reducer":"grant_credit"},"settleMs":0},{"actor":"staff","do":"expectActionOutcome","outcome":"accepted"},{"actor":"owner","do":"reload","settleMs":1000},{"actor":"owner","do":"ensureSignedIn","name":"credit-owner-753","readyTestid":"current-user"},{"actor":"owner","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"owner","do":"click","testid":"credit-link","unlessVisible":"credit-balance"},{"actor":"owner","do":"expectNumber","equals":10,"testid":"credit-balance","within":10000}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.store-credit","requiresFeatures":["ecommerce.feature.store-credit"],"role":"guarantee","source":"scenarios/progression-store-credit.json"},{"checkGroupId":"production-754","feature":{"actors":["owner","staff","tab"],"criteria":[{"id":"754a","steps":[{"action":"checkoutCredit","actors":["owner","tab"],"do":"callConcurrently","namedAction":{"args":[],"id":"checkoutCredit","method":"POST","path":"/api/checkout/credit","reducer":"checkout_credit"},"settleMs":0},{"do":"expectCallOutcomes"},{"actor":"owner","do":"freshClient"},{"actor":"owner-fresh","do":"signIn","name":"credit-owner-754"},{"actor":"owner-fresh","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"owner-fresh","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"owner-fresh","contains":"Desk Lamp","do":"expectElementCount","equals":1,"testid":"order-item","within":10000},{"actor":"owner-fresh","do":"expectNumber","equals":10,"in":{"contains":"Desk Lamp","testid":"order-item"},"testid":"payment-credit-amount"},{"actor":"owner-fresh","do":"expectNumber","equals":32,"in":{"contains":"Desk Lamp","testid":"order-item"},"testid":"payment-external-amount"},{"actor":"owner-fresh","do":"expectNumber","equals":42,"in":{"contains":"Desk Lamp","testid":"order-item"},"testid":"payment-amount"},{"actor":"owner-fresh","do":"click","testid":"credit-link","unlessVisible":"credit-panel"},{"actor":"owner-fresh","attribute":"aria-busy","do":"expect","testid":"credit-panel","value":"false","within":10000},{"actor":"owner-fresh","do":"expectNumber","equals":0,"testid":"credit-balance"}]}],"id":754,"setup":[{"actor":"owner","do":"signUp","name":"credit-owner-754"},{"actor":"owner","do":"click","testid":"credit-link","unlessVisible":"credit-panel"},{"actor":"owner","attribute":"aria-busy","do":"expect","testid":"credit-panel","value":"false","within":10000},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"staff","do":"click","testid":"credit-link","unlessVisible":"credit-panel"},{"actor":"staff","attribute":"aria-busy","do":"expect","testid":"credit-panel","value":"false","within":10000},{"actor":"staff","do":"fill","testid":"credit-amount-input","text":"10.00"},{"actor":"staff","do":"fill","testid":"credit-reference-input","text":"credit-754"},{"action":"grantCredit","actor":"staff","do":"callAction","from":"staff","input":{"attribute":"data-action-input","overrides":{"accountId":{"actor":"owner","attribute":"data-account-id","testid":"credit-panel"}},"testid":"credit-grant"},"namedAction":{"args":[0,1000,""],"id":"grantCredit","method":"POST","params":[{"in":"body","name":"accountId","wireType":"u64"},{"in":"body","name":"amountMinor"},{"in":"body","name":"reference"}],"path":"/api/staff/credit","reducer":"grant_credit"},"settleMs":0},{"actor":"staff","do":"expectActionOutcome","outcome":"accepted"},{"actor":"owner","do":"reload","settleMs":1000},{"actor":"owner","do":"ensureSignedIn","name":"credit-owner-754","readyTestid":"current-user"},{"actor":"owner","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"owner","do":"click","testid":"credit-link","unlessVisible":"credit-balance"},{"actor":"owner","do":"expectNumber","equals":10,"testid":"credit-balance","within":10000},{"actor":"owner","do":"click","testid":"catalog-link"},{"actor":"owner","do":"click","in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"add-to-cart"},{"actor":"owner","do":"click","testid":"cart-toggle"},{"actor":"owner","do":"expectNumber","equals":42,"testid":"cart-total"},{"actor":"tab","do":"signIn","name":"credit-owner-754"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.store-credit","requiresFeatures":["ecommerce.feature.store-credit"],"role":"guarantee","source":"scenarios/progression-store-credit.json"},{"checkGroupId":"production-755","feature":{"actors":["owner","staff","tab"],"criteria":[{"id":"755a","steps":[{"do":"restartBackend","settleMs":1000},{"actor":"owner","do":"freshClient"},{"actor":"owner-fresh","do":"signIn","name":"credit-owner-755"},{"actor":"owner-fresh","do":"click","testid":"credit-link","unlessVisible":"credit-panel"},{"actor":"owner-fresh","attribute":"aria-busy","do":"expect","testid":"credit-panel","value":"false","within":10000},{"actor":"owner-fresh","do":"expectNumber","equals":10,"testid":"credit-balance"}]}],"id":755,"setup":[{"actor":"owner","do":"signUp","name":"credit-owner-755"},{"actor":"owner","do":"click","testid":"credit-link","unlessVisible":"credit-panel"},{"actor":"owner","attribute":"aria-busy","do":"expect","testid":"credit-panel","value":"false","within":10000},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"staff","do":"click","testid":"credit-link","unlessVisible":"credit-panel"},{"actor":"staff","attribute":"aria-busy","do":"expect","testid":"credit-panel","value":"false","within":10000},{"actor":"staff","do":"fill","testid":"credit-amount-input","text":"10.00"},{"actor":"staff","do":"fill","testid":"credit-reference-input","text":"credit-755"},{"action":"grantCredit","actor":"staff","do":"callAction","from":"staff","input":{"attribute":"data-action-input","overrides":{"accountId":{"actor":"owner","attribute":"data-account-id","testid":"credit-panel"}},"testid":"credit-grant"},"namedAction":{"args":[0,1000,""],"id":"grantCredit","method":"POST","params":[{"in":"body","name":"accountId","wireType":"u64"},{"in":"body","name":"amountMinor"},{"in":"body","name":"reference"}],"path":"/api/staff/credit","reducer":"grant_credit"},"settleMs":0},{"actor":"staff","do":"expectActionOutcome","outcome":"accepted"},{"actor":"owner","do":"reload","settleMs":1000},{"actor":"owner","do":"ensureSignedIn","name":"credit-owner-755","readyTestid":"current-user"},{"actor":"owner","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"owner","do":"click","testid":"credit-link","unlessVisible":"credit-balance"},{"actor":"owner","do":"expectNumber","equals":10,"testid":"credit-balance","within":10000}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.store-credit","requiresFeatures":["ecommerce.feature.store-credit"],"role":"guarantee","source":"scenarios/progression-store-credit.json"}],"id":"selected-source-105","scenario":{"level":5,"writeUrlPattern":null},"source":"scenarios/progression-store-credit.json"},{"checkGroups":[{"checkGroupId":"subscriptions-760","feature":{"actors":["owner","other"],"criteria":[{"id":"760a","steps":[{"actor":"owner","do":"freshClient"},{"actor":"owner-fresh","do":"signIn","name":"subscription-760"},{"actor":"owner-fresh","do":"click","testid":"subscriptions-link","unlessVisible":"subscriptions-panel"},{"actor":"owner-fresh","attribute":"aria-busy","do":"expect","testid":"subscriptions-panel","value":"false","within":10000},{"actor":"owner-fresh","do":"expect","in":{"contains":"Desk Lamp","testid":"subscription-row"},"testid":"subscription-status","value":"complete","within":90000},{"actor":"owner-fresh","do":"expectElementCount","equals":2,"in":{"contains":"Desk Lamp","testid":"subscription-row"},"testid":"subscription-delivery"},{"actor":"owner-fresh","do":"expectSequence","equals":["paid","paid"],"in":{"contains":"Desk Lamp","testid":"subscription-row"},"testid":"subscription-delivery-status"},{"actor":"owner-fresh","do":"expectNumber","equals":84,"in":{"contains":"Desk Lamp","testid":"subscription-row"},"testid":"subscription-total"},{"do":"dbExpectStock","equals":8,"item":"Desk Lamp"},{"actor":"owner-fresh","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"owner-fresh","do":"click","testid":"orders-toggle"},{"actor":"owner-fresh","contains":"Desk Lamp","do":"expectElementCount","equals":2,"testid":"order-item","within":10000},{"actor":"owner-fresh","do":"expectElementCount","equals":2,"testid":"payment-record"}]}],"id":760,"setup":[{"actor":"owner","do":"signUp","name":"subscription-760"},{"do":"dbSetStock","item":"Desk Lamp","quantity":10,"settleMs":0,"warehouse":"East"},{"do":"dbSetStock","item":"Desk Lamp","quantity":0,"settleMs":0,"warehouse":"West"},{"actor":"owner","do":"click","testid":"subscriptions-link","unlessVisible":"subscriptions-panel"},{"actor":"owner","attribute":"aria-busy","do":"expect","testid":"subscriptions-panel","value":"false","within":10000},{"actor":"owner","do":"fill","testid":"subscription-item-input","text":"Desk Lamp"},{"actor":"owner","do":"fill","testid":"subscription-quantity-input","text":"1"},{"actor":"owner","do":"fill","testid":"subscription-interval-input","text":"30"},{"actor":"owner","do":"fill","testid":"subscription-deliveries-input","text":"2"},{"actor":"owner","do":"click","testid":"subscription-create"},{"actor":"owner","do":"expect","in":{"contains":"Desk Lamp","testid":"subscription-row"},"testid":"subscription-status","value":"active","within":10000}]},"packId":"ecommerce.feature.subscriptions","role":"feature","source":"scenarios/progression-subscriptions.json"},{"checkGroupId":"production-761","feature":{"actors":["owner","other"],"criteria":[{"id":"761a","steps":[{"do":"restartBackend","settleMs":1000},{"actor":"owner","do":"freshClient"},{"actor":"owner-fresh","do":"signIn","name":"subscription-761"},{"actor":"owner-fresh","do":"click","testid":"subscriptions-link","unlessVisible":"subscriptions-panel"},{"actor":"owner-fresh","attribute":"aria-busy","do":"expect","testid":"subscriptions-panel","value":"false","within":10000},{"actor":"owner-fresh","do":"expect","in":{"contains":"Desk Lamp","testid":"subscription-row"},"testid":"subscription-status","value":"complete","within":90000},{"actor":"owner-fresh","do":"expectElementCount","equals":2,"in":{"contains":"Desk Lamp","testid":"subscription-row"},"testid":"subscription-delivery"},{"actor":"owner-fresh","do":"expectSequence","equals":["paid","paid"],"in":{"contains":"Desk Lamp","testid":"subscription-row"},"testid":"subscription-delivery-status"},{"actor":"owner-fresh","do":"expectNumber","equals":84,"in":{"contains":"Desk Lamp","testid":"subscription-row"},"testid":"subscription-total"},{"do":"dbExpectStock","equals":8,"item":"Desk Lamp"},{"actor":"owner-fresh","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"owner-fresh","do":"click","testid":"orders-toggle"},{"actor":"owner-fresh","contains":"Desk Lamp","do":"expectElementCount","equals":2,"testid":"order-item","within":10000},{"actor":"owner-fresh","do":"expectElementCount","equals":2,"testid":"payment-record"},{"do":"restartBackend","settleMs":1000},{"actor":"owner","do":"freshClient"},{"actor":"owner-fresh","do":"signIn","name":"subscription-761"},{"actor":"owner-fresh","do":"click","testid":"subscriptions-link","unlessVisible":"subscriptions-panel"},{"actor":"owner-fresh","attribute":"aria-busy","do":"expect","testid":"subscriptions-panel","value":"false","within":10000},{"actor":"owner-fresh","do":"expect","in":{"contains":"Desk Lamp","testid":"subscription-row"},"testid":"subscription-status","value":"complete","within":90000},{"actor":"owner-fresh","do":"expectElementCount","equals":2,"in":{"contains":"Desk Lamp","testid":"subscription-row"},"testid":"subscription-delivery"},{"actor":"owner-fresh","do":"expectSequence","equals":["paid","paid"],"in":{"contains":"Desk Lamp","testid":"subscription-row"},"testid":"subscription-delivery-status"},{"actor":"owner-fresh","do":"expectNumber","equals":84,"in":{"contains":"Desk Lamp","testid":"subscription-row"},"testid":"subscription-total"},{"do":"dbExpectStock","equals":8,"item":"Desk Lamp"},{"actor":"owner-fresh","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"owner-fresh","do":"click","testid":"orders-toggle"},{"actor":"owner-fresh","contains":"Desk Lamp","do":"expectElementCount","equals":2,"testid":"order-item","within":10000},{"actor":"owner-fresh","do":"expectElementCount","equals":2,"testid":"payment-record"}]}],"id":761,"setup":[{"actor":"owner","do":"signUp","name":"subscription-761"},{"do":"dbSetStock","item":"Desk Lamp","quantity":10,"settleMs":0,"warehouse":"East"},{"do":"dbSetStock","item":"Desk Lamp","quantity":0,"settleMs":0,"warehouse":"West"},{"actor":"owner","do":"click","testid":"subscriptions-link","unlessVisible":"subscriptions-panel"},{"actor":"owner","attribute":"aria-busy","do":"expect","testid":"subscriptions-panel","value":"false","within":10000},{"actor":"owner","do":"fill","testid":"subscription-item-input","text":"Desk Lamp"},{"actor":"owner","do":"fill","testid":"subscription-quantity-input","text":"1"},{"actor":"owner","do":"fill","testid":"subscription-interval-input","text":"30"},{"actor":"owner","do":"fill","testid":"subscription-deliveries-input","text":"2"},{"actor":"owner","do":"click","testid":"subscription-create"},{"actor":"owner","do":"expect","in":{"contains":"Desk Lamp","testid":"subscription-row"},"testid":"subscription-status","value":"active","within":10000}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.subscriptions","requiresFeatures":["ecommerce.feature.subscriptions"],"role":"guarantee","source":"scenarios/progression-subscriptions.json"},{"checkGroupId":"production-762","feature":{"actors":["owner","other"],"criteria":[{"id":"762a","steps":[{"action":"cancelSubscription","actor":"other","do":"callAction","from":"owner","input":{"attribute":"data-action-input","testid":"subscription-cancel"},"namedAction":{"args":[0],"id":"cancelSubscription","method":"POST","params":[{"in":"path","name":"subscriptionId","placeholder":"{subscriptionId}","wireType":"u64"}],"path":"/api/subscriptions/{subscriptionId}/cancel","reducer":"cancel_subscription"},"settleMs":0},{"actor":"other","do":"expectActionOutcome","outcome":"refused"},{"actor":"owner","do":"expect","in":{"contains":"Desk Lamp","testid":"subscription-row"},"testid":"subscription-status","value":"active","within":10000},{"actor":"owner","do":"click","in":{"contains":"Desk Lamp","testid":"subscription-row"},"testid":"subscription-cancel"},{"actor":"owner","do":"freshClient"},{"actor":"owner-fresh","do":"signIn","name":"subscription-762"},{"actor":"owner-fresh","do":"click","testid":"subscriptions-link","unlessVisible":"subscriptions-panel"},{"actor":"owner-fresh","attribute":"aria-busy","do":"expect","testid":"subscriptions-panel","value":"false","within":10000},{"actor":"owner-fresh","do":"expect","in":{"contains":"Desk Lamp","testid":"subscription-row"},"testid":"subscription-status","value":"cancelled","within":10000},{"actor":"owner-fresh","as":"deliveries-at-cancel","count":true,"do":"recordNumber","in":{"contains":"Desk Lamp","testid":"subscription-row"},"testid":"subscription-delivery"},{"as":"stock-at-cancel","do":"dbRecordStock","item":"Desk Lamp"},{"actor":"owner-fresh","do":"wait","ms":65000},{"actor":"owner-fresh","do":"expectElementCount","in":{"contains":"Desk Lamp","testid":"subscription-row"},"plus":0,"relativeTo":"deliveries-at-cancel","testid":"subscription-delivery"},{"do":"dbExpectStock","item":"Desk Lamp","plus":0,"relativeTo":"stock-at-cancel"}]}],"id":762,"setup":[{"actor":"other","do":"signUp","name":"subscription-other-762"},{"actor":"owner","do":"signUp","name":"subscription-762"},{"do":"dbSetStock","item":"Desk Lamp","quantity":10,"settleMs":0,"warehouse":"East"},{"do":"dbSetStock","item":"Desk Lamp","quantity":0,"settleMs":0,"warehouse":"West"},{"actor":"owner","do":"click","testid":"subscriptions-link","unlessVisible":"subscriptions-panel"},{"actor":"owner","attribute":"aria-busy","do":"expect","testid":"subscriptions-panel","value":"false","within":10000},{"actor":"owner","do":"fill","testid":"subscription-item-input","text":"Desk Lamp"},{"actor":"owner","do":"fill","testid":"subscription-quantity-input","text":"1"},{"actor":"owner","do":"fill","testid":"subscription-interval-input","text":"30"},{"actor":"owner","do":"fill","testid":"subscription-deliveries-input","text":"2"},{"actor":"owner","do":"click","testid":"subscription-create"},{"actor":"owner","do":"expect","in":{"contains":"Desk Lamp","testid":"subscription-row"},"testid":"subscription-status","value":"active","within":10000}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.subscriptions","requiresFeatures":["ecommerce.feature.subscriptions"],"role":"guarantee","source":"scenarios/progression-subscriptions.json"},{"checkGroupId":"production-763","feature":{"actors":["owner","other"],"criteria":[{"id":"763a","steps":[{"actor":"owner","do":"click","in":{"contains":"Desk Lamp","testid":"subscription-row"},"testid":"subscription-pause"},{"actor":"owner","do":"expect","in":{"contains":"Desk Lamp","testid":"subscription-row"},"testid":"subscription-status","value":"paused","within":10000},{"do":"restartBackend","settleMs":1000},{"actor":"owner","do":"freshClient"},{"actor":"owner-fresh","do":"signIn","name":"subscription-763"},{"actor":"owner-fresh","do":"click","testid":"subscriptions-link","unlessVisible":"subscriptions-panel"},{"actor":"owner-fresh","attribute":"aria-busy","do":"expect","testid":"subscriptions-panel","value":"false","within":10000},{"actor":"owner-fresh","do":"expect","in":{"contains":"Desk Lamp","testid":"subscription-row"},"testid":"subscription-status","value":"paused","within":10000},{"actor":"owner-fresh","as":"deliveries-at-pause","count":true,"do":"recordNumber","in":{"contains":"Desk Lamp","testid":"subscription-row"},"testid":"subscription-delivery"},{"as":"stock-at-pause","do":"dbRecordStock","item":"Desk Lamp"},{"actor":"owner-fresh","do":"wait","ms":35000},{"actor":"owner-fresh","do":"expectElementCount","in":{"contains":"Desk Lamp","testid":"subscription-row"},"plus":0,"relativeTo":"deliveries-at-pause","testid":"subscription-delivery"},{"do":"dbExpectStock","item":"Desk Lamp","plus":0,"relativeTo":"stock-at-pause"},{"actor":"owner-fresh","do":"click","in":{"contains":"Desk Lamp","testid":"subscription-row"},"testid":"subscription-resume"},{"actor":"owner","do":"freshClient"},{"actor":"owner-fresh","do":"signIn","name":"subscription-763"},{"actor":"owner-fresh","do":"click","testid":"subscriptions-link","unlessVisible":"subscriptions-panel"},{"actor":"owner-fresh","attribute":"aria-busy","do":"expect","testid":"subscriptions-panel","value":"false","within":10000},{"actor":"owner-fresh","do":"expect","in":{"contains":"Desk Lamp","testid":"subscription-row"},"testid":"subscription-status","value":"complete","within":90000},{"actor":"owner-fresh","do":"expectElementCount","equals":2,"in":{"contains":"Desk Lamp","testid":"subscription-row"},"testid":"subscription-delivery"},{"actor":"owner-fresh","do":"expectSequence","equals":["paid","paid"],"in":{"contains":"Desk Lamp","testid":"subscription-row"},"testid":"subscription-delivery-status"},{"actor":"owner-fresh","do":"expectNumber","equals":84,"in":{"contains":"Desk Lamp","testid":"subscription-row"},"testid":"subscription-total"},{"do":"dbExpectStock","equals":8,"item":"Desk Lamp"},{"actor":"owner-fresh","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"owner-fresh","do":"click","testid":"orders-toggle"},{"actor":"owner-fresh","contains":"Desk Lamp","do":"expectElementCount","equals":2,"testid":"order-item","within":10000},{"actor":"owner-fresh","do":"expectElementCount","equals":2,"testid":"payment-record"}]}],"id":763,"setup":[{"actor":"owner","do":"signUp","name":"subscription-763"},{"do":"dbSetStock","item":"Desk Lamp","quantity":10,"settleMs":0,"warehouse":"East"},{"do":"dbSetStock","item":"Desk Lamp","quantity":0,"settleMs":0,"warehouse":"West"},{"actor":"owner","do":"click","testid":"subscriptions-link","unlessVisible":"subscriptions-panel"},{"actor":"owner","attribute":"aria-busy","do":"expect","testid":"subscriptions-panel","value":"false","within":10000},{"actor":"owner","do":"fill","testid":"subscription-item-input","text":"Desk Lamp"},{"actor":"owner","do":"fill","testid":"subscription-quantity-input","text":"1"},{"actor":"owner","do":"fill","testid":"subscription-interval-input","text":"30"},{"actor":"owner","do":"fill","testid":"subscription-deliveries-input","text":"2"},{"actor":"owner","do":"click","testid":"subscription-create"},{"actor":"owner","do":"expect","in":{"contains":"Desk Lamp","testid":"subscription-row"},"testid":"subscription-status","value":"active","within":10000}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.subscriptions","requiresFeatures":["ecommerce.feature.subscriptions"],"role":"guarantee","source":"scenarios/progression-subscriptions.json"}],"id":"selected-source-106","scenario":{"level":5,"writeUrlPattern":null},"source":"scenarios/progression-subscriptions.json"},{"checkGroups":[{"checkGroupId":"support-history","feature":{"actors":["owner","other"],"criteria":[{"id":"612c","steps":[{"actor":"owner","do":"reload","settleMs":1000},{"actor":"owner","do":"ensureSignedIn","name":"support-owner","readyTestid":"current-user"},{"actor":"owner","do":"click","testid":"support-link","unlessVisible":"support-ticket"},{"actor":"owner","contains":"Owner ticket {user:ticketmarker}","do":"expect","testid":"support-ticket"}]}],"id":612,"setup":[{"actor":"owner","do":"signUp","name":"support-owner"},{"actor":"owner","do":"click","testid":"support-link"},{"actor":"owner","do":"fill","testid":"support-email","text":"owner@example.com"},{"actor":"owner","do":"fill","testid":"support-subject","text":"Owner ticket {user:ticketmarker}"},{"actor":"owner","do":"fill","testid":"support-message","text":"Private account issue."},{"actor":"owner","do":"click","testid":"support-submit"},{"actor":"owner","do":"expect","nonEmpty":true,"testid":"support-reference"},{"actor":"other","do":"signUp","name":"support-other"}]},"packId":"ecommerce.progression.support-history","role":"feature","source":"scenarios/progression-support-history.json"},{"checkGroupId":"support-history-reload","feature":{"actors":["owner","other"],"criteria":[{"id":"612a","steps":[{"actor":"owner","do":"reload","settleMs":3000},{"actor":"owner","do":"ensureSignedIn","name":"support-owner","readyTestid":"current-user"},{"actor":"owner","do":"click","testid":"support-link"},{"actor":"owner","contains":"Owner ticket {user:ticketmarker}","do":"expect","testid":"support-ticket"},{"do":"restartBackend","settleMs":1000},{"actor":"owner","do":"freshClient"},{"actor":"owner-fresh","do":"signIn","name":"support-owner"},{"actor":"owner-fresh","do":"click","testid":"support-link"},{"actor":"owner-fresh","contains":"Owner ticket {user:ticketmarker}","do":"expect","testid":"support-ticket"}]}],"id":612,"setup":[{"actor":"owner","do":"signUp","name":"support-owner"},{"actor":"owner","do":"click","testid":"support-link"},{"actor":"owner","do":"fill","testid":"support-email","text":"owner@example.com"},{"actor":"owner","do":"fill","testid":"support-subject","text":"Owner ticket {user:ticketmarker}"},{"actor":"owner","do":"fill","testid":"support-message","text":"Private account issue."},{"actor":"owner","do":"click","testid":"support-submit"},{"actor":"owner","do":"expect","nonEmpty":true,"testid":"support-reference"},{"actor":"other","do":"signUp","name":"support-other"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.state-durability","requiresFeatures":["ecommerce.progression.support-history"],"role":"guarantee","source":"scenarios/progression-support-history.json"},{"checkGroupId":"support-history-privacy","feature":{"actors":["owner","other"],"criteria":[{"id":"612b","steps":[{"actor":"owner","do":"reload","settleMs":1000},{"actor":"owner","do":"ensureSignedIn","name":"support-owner","readyTestid":"current-user"},{"actor":"owner","do":"click","testid":"support-link"},{"actor":"owner","do":"fill","testid":"support-email","text":"owner@example.com"},{"actor":"owner","do":"fill","testid":"support-subject","text":"Private ticket {user:privateticketmarker}"},{"actor":"owner","do":"fill","testid":"support-message","text":"Private account issue."},{"actor":"owner","do":"click","testid":"support-submit"},{"actor":"owner","do":"expect","nonEmpty":true,"testid":"support-reference"},{"actor":"owner","do":"reload","settleMs":1000},{"actor":"owner","do":"ensureSignedIn","name":"support-owner","readyTestid":"current-user"},{"actor":"owner","do":"click","testid":"support-link"},{"actor":"owner","contains":"Private ticket {user:privateticketmarker}","do":"expect","testid":"support-ticket"},{"actor":"owner","contains":"Private ticket {user:privateticketmarker}","do":"expectReceived","within":10000},{"actor":"other","do":"reload","settleMs":0},{"actor":"other","do":"ensureSignedIn","name":"support-other","readyTestid":"current-user"},{"actor":"other","do":"click","testid":"support-link"},{"absent":true,"actor":"other","contains":"Private ticket {user:privateticketmarker}","do":"expect","testid":"support-ticket"},{"actor":"other","contains":"Private ticket {user:privateticketmarker}","do":"expectNotReceived"}]}],"id":612,"setup":[{"actor":"owner","do":"signUp","name":"support-owner"},{"actor":"owner","do":"click","testid":"support-link"},{"actor":"owner","do":"fill","testid":"support-email","text":"owner@example.com"},{"actor":"owner","do":"fill","testid":"support-subject","text":"Owner ticket {user:ticketmarker}"},{"actor":"owner","do":"fill","testid":"support-message","text":"Private account issue."},{"actor":"owner","do":"click","testid":"support-submit"},{"actor":"owner","do":"expect","nonEmpty":true,"testid":"support-reference"},{"actor":"other","do":"signUp","name":"support-other"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","requiresFeatures":["ecommerce.progression.support-history"],"role":"guarantee","source":"scenarios/progression-support-history.json"},{"checkGroupId":"support-history-logout","feature":{"actors":["owner","other"],"criteria":[{"id":"612d","steps":[{"actor":"owner","do":"reload","settleMs":1000},{"actor":"owner","do":"ensureSignedIn","name":"support-owner","readyTestid":"current-user"},{"actor":"owner","do":"click","testid":"support-link"},{"actor":"owner","do":"fill","testid":"support-email","text":"owner@example.com"},{"actor":"owner","do":"fill","testid":"support-subject","text":"Logout ticket {user:logoutticketmarker}"},{"actor":"owner","do":"fill","testid":"support-message","text":"Private account issue."},{"actor":"owner","do":"click","testid":"support-submit"},{"actor":"owner","do":"expect","nonEmpty":true,"testid":"support-reference"},{"actor":"owner","do":"reload","settleMs":1000},{"actor":"owner","do":"ensureSignedIn","name":"support-owner","readyTestid":"current-user"},{"actor":"owner","do":"click","testid":"support-link","unlessVisible":"support-ticket"},{"actor":"owner","contains":"Logout ticket {user:logoutticketmarker}","do":"expect","testid":"support-ticket"},{"actor":"owner","contains":"Logout ticket {user:logoutticketmarker}","do":"expectReceived","within":10000},{"actor":"owner","do":"reload","settleMs":1000},{"actor":"owner","do":"ensureSignedIn","name":"support-owner","readyTestid":"current-user"},{"actor":"owner","do":"click","testid":"current-user","unlessVisible":"signout"},{"actor":"owner","do":"click","testid":"signout"},{"actor":"owner","do":"waitUntilAbsent","testid":"current-user","within":6000},{"actor":"owner","do":"freshClient","preserveStorage":true},{"absent":true,"actor":"owner-fresh","do":"expect","testid":"current-user"},{"actor":"owner-fresh","do":"click","testid":"support-link"},{"actor":"owner-fresh","do":"expect","testid":"support-email"},{"absent":true,"actor":"owner-fresh","contains":"Logout ticket {user:logoutticketmarker}","do":"expect","testid":"support-ticket"},{"actor":"owner-fresh","contains":"Logout ticket {user:logoutticketmarker}","do":"expectNotReceived"}]}],"id":612,"setup":[{"actor":"owner","do":"signUp","name":"support-owner"},{"actor":"owner","do":"click","testid":"support-link"},{"actor":"owner","do":"fill","testid":"support-email","text":"owner@example.com"},{"actor":"owner","do":"fill","testid":"support-subject","text":"Owner ticket {user:ticketmarker}"},{"actor":"owner","do":"fill","testid":"support-message","text":"Private account issue."},{"actor":"owner","do":"click","testid":"support-submit"},{"actor":"owner","do":"expect","nonEmpty":true,"testid":"support-reference"},{"actor":"other","do":"signUp","name":"support-other"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","requiresFeatures":["ecommerce.progression.support-history"],"role":"guarantee","source":"scenarios/progression-support-history.json"}],"id":"selected-source-107","scenario":{"level":2,"writeUrlPattern":null},"source":"scenarios/progression-support-history.json"},{"checkGroups":[{"checkGroupId":"support-intake","feature":{"actors":["visitor"],"criteria":[{"id":"610a","steps":[{"actor":"visitor","do":"click","testid":"support-link"},{"actor":"visitor","do":"fill","testid":"support-email","text":"visitor@example.com"},{"actor":"visitor","do":"fill","testid":"support-subject","text":"Damaged package"},{"actor":"visitor","do":"fill","testid":"support-message","text":"The package arrived damaged."},{"actor":"visitor","do":"click","testid":"support-submit"},{"actor":"visitor","do":"expect","nonEmpty":true,"testid":"support-reference"}]}],"id":610,"setup":[]},"packId":"ecommerce.progression.support-intake","role":"feature","source":"scenarios/progression-support-intake.json"}],"id":"selected-source-108","scenario":{"level":1,"writeUrlPattern":null},"source":"scenarios/progression-support-intake.json"},{"checkGroups":[{"checkGroupId":"support-refund-access","feature":{"actors":["owner","staff"],"criteria":[{"id":"615c","steps":[{"absent":true,"actor":"owner","do":"expect","testid":"support-refund"},{"action":"supportRefund","actor":"owner","authentication":"actor","do":"callAction","from":"staff","input":{"attribute":"data-action-input","testid":"support-refund"},"namedAction":{"args":[0],"id":"supportRefund","method":"POST","params":[{"in":"path","name":"caseId","placeholder":"{caseId}","wireType":"u64"}],"path":"/api/support/cases/{caseId}/refund","reducer":"support_refund"},"settleMs":1500},{"actor":"owner","do":"expectActionOutcome","outcome":"refused"},{"actor":"owner","do":"reload","settleMs":1000},{"actor":"owner","do":"ensureSignedIn","name":"refund-access-owner","readyTestid":"current-user"},{"actor":"owner","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"owner","do":"click","testid":"support-link","unlessVisible":"support-subject"},{"actor":"owner","do":"expect","in":{"contains":"Access refund case","testid":"support-ticket"},"notContains":"resolved","testid":"support-status"},{"actor":"owner","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"owner","do":"click","testid":"orders-toggle"},{"actor":"owner","do":"expect","in":{"contains":"Keyboard","testid":"order-item"},"testid":"order-status","value":"pending"},{"absent":true,"actor":"owner","contains":"Keyboard","do":"expect","testid":"refund-entry"}]}],"id":615,"setup":[{"actor":"owner","do":"signUp","name":"refund-access-owner"},{"actor":"owner","do":"click","in":{"contains":"Keyboard","testid":"item-card"},"testid":"buy-now"},{"actor":"owner","do":"click","testid":"support-link"},{"actor":"owner","do":"fill","testid":"support-subject","text":"Access refund case"},{"actor":"owner","do":"fill","testid":"support-message","text":"This refund requires staff approval."},{"actor":"owner","do":"click","testid":"support-submit"},{"actor":"owner","contains":"Keyboard","do":"click","in":{"contains":"Access refund case","testid":"support-ticket"},"testid":"support-order-option"},{"actor":"owner","do":"click","in":{"contains":"Access refund case","testid":"support-ticket"},"testid":"support-link-order"},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"staff","do":"click","testid":"staff-link","unlessVisible":"support-assignee"},{"actor":"staff","do":"click","ifAvailable":true,"testid":"support-queue-link","unlessVisible":"support-assignee","within":1000}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","requiresFeatures":["ecommerce.progression.support-refunds"],"role":"guarantee","source":"scenarios/progression-support-refunds-access.json"}],"id":"selected-source-109","scenario":{"level":5,"writeUrlPattern":null},"source":"scenarios/progression-support-refunds-access.json"},{"checkGroups":[{"checkGroupId":"support-refund-accounting","feature":{"actors":["owner","staff"],"criteria":[{"id":"615b","steps":[{"actor":"staff","do":"click","in":{"contains":"Accounting refund case","testid":"support-ticket"},"testid":"support-refund"},{"actor":"owner","do":"reload","settleMs":1000},{"actor":"owner","do":"ensureSignedIn","name":"refund-accounting-owner","readyTestid":"current-user"},{"actor":"owner","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"owner","do":"click","testid":"support-link","unlessVisible":"support-subject"},{"actor":"owner","do":"expectNumber","in":{"contains":"Accounting refund case","testid":"support-ticket"},"plus":0,"relativeTo":"paid-total","testid":"support-refund-total","within":10000},{"actor":"owner","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"owner","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"owner","do":"expectNumber","in":{"contains":"Keyboard","testid":"order-item"},"plus":0,"relativeTo":"paid-total","testid":"order-refund-total","within":10000},{"actor":"owner","contains":"Keyboard","do":"expectElementCount","equals":1,"testid":"refund-entry","within":10000},{"actor":"staff","do":"replayAs","from":"staff","match":"refund","namedAction":{"args":[0],"id":"supportRefund","method":"POST","params":[{"in":"path","name":"caseId","placeholder":"{caseId}","wireType":"u64"}],"path":"/api/support/cases/{caseId}/refund","reducer":"support_refund"},"namedTarget":{"attribute":"data-entity-id","contains":"Accounting refund case","testid":"support-ticket","valueType":"string"},"settleMs":1500},{"actor":"staff","do":"expectReplayCompleted"},{"actor":"owner","do":"freshClient"},{"actor":"owner-fresh","do":"signIn","name":"refund-accounting-owner"},{"actor":"owner-fresh","do":"click","testid":"support-link"},{"actor":"owner-fresh","do":"expectNumber","in":{"contains":"Accounting refund case","testid":"support-ticket"},"plus":0,"relativeTo":"paid-total","testid":"support-refund-total","within":10000},{"actor":"owner-fresh","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"owner-fresh","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"owner-fresh","do":"expectNumber","in":{"contains":"Keyboard","testid":"order-item"},"plus":0,"relativeTo":"paid-total","testid":"order-refund-total","within":10000},{"actor":"owner-fresh","contains":"Keyboard","do":"expectElementCount","equals":1,"testid":"refund-entry","within":10000},{"actor":"owner-fresh","do":"expectNumber","equals":0,"in":{"contains":"Mouse","testid":"order-item"},"testid":"order-refund-total","within":10000},{"actor":"owner-fresh","contains":"Mouse","do":"expectElementCount","equals":0,"testid":"refund-entry","within":10000}]}],"id":615,"setup":[{"actor":"owner","do":"signUp","name":"refund-accounting-owner"},{"actor":"owner","do":"click","in":{"contains":"Mouse","testid":"item-card"},"testid":"buy-now"},{"actor":"owner","do":"click","in":{"contains":"Keyboard","testid":"item-card"},"testid":"buy-now"},{"actor":"owner","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"owner","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"owner","as":"paid-total","do":"recordNumber","in":{"contains":"Keyboard","testid":"order-item"},"testid":"order-total"},{"actor":"owner","do":"click","testid":"support-link"},{"actor":"owner","do":"fill","testid":"support-subject","text":"Accounting refund case"},{"actor":"owner","do":"fill","testid":"support-message","text":"Refund the exact amount paid."},{"actor":"owner","do":"click","testid":"support-submit"},{"actor":"owner","contains":"Keyboard","do":"click","in":{"contains":"Accounting refund case","testid":"support-ticket"},"testid":"support-order-option"},{"actor":"owner","do":"click","in":{"contains":"Accounting refund case","testid":"support-ticket"},"testid":"support-link-order"},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"staff","do":"click","testid":"staff-link","unlessVisible":"support-assignee"},{"actor":"staff","do":"click","ifAvailable":true,"testid":"support-queue-link","unlessVisible":"support-assignee","within":1000}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.transactional-integrity","requiresFeatures":["ecommerce.progression.support-refunds"],"role":"guarantee","source":"scenarios/progression-support-refunds-accounting.json"}],"id":"selected-source-110","scenario":{"level":5,"writeUrlPattern":null},"source":"scenarios/progression-support-refunds-accounting.json"},{"checkGroups":[{"checkGroupId":"support-refunds-resolution","feature":{"actors":["owner","staff"],"criteria":[{"id":"615a","steps":[{"actor":"staff","do":"click","in":{"contains":"Resolution refund case","testid":"support-ticket"},"testid":"support-refund"},{"actor":"owner","contains":"resolved","do":"expect","in":{"contains":"Resolution refund case","testid":"support-ticket"},"testid":"support-status","within":10000},{"actor":"owner","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"owner","do":"click","testid":"orders-toggle"},{"actor":"owner","contains":"refunded","do":"expect","in":{"contains":"Keyboard","testid":"order-item"},"testid":"order-status","within":10000}]}],"id":615,"setup":[{"actor":"owner","do":"signUp","name":"refund-resolution-owner"},{"actor":"owner","do":"click","in":{"contains":"Keyboard","testid":"item-card"},"testid":"buy-now"},{"actor":"owner","do":"click","testid":"support-link"},{"actor":"owner","do":"fill","testid":"support-subject","text":"Resolution refund case"},{"actor":"owner","do":"fill","testid":"support-message","text":"Please refund my Keyboard order."},{"actor":"owner","do":"click","testid":"support-submit"},{"actor":"owner","contains":"Keyboard","do":"click","in":{"contains":"Resolution refund case","testid":"support-ticket"},"testid":"support-order-option"},{"actor":"owner","do":"click","in":{"contains":"Resolution refund case","testid":"support-ticket"},"testid":"support-link-order"},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"staff","do":"click","testid":"staff-link","unlessVisible":"support-assignee"},{"actor":"staff","do":"click","ifAvailable":true,"testid":"support-queue-link","unlessVisible":"support-assignee"}]},"packId":"ecommerce.progression.support-refunds","role":"feature","source":"scenarios/progression-support-refunds-resolution.json"}],"id":"selected-source-111","scenario":{"level":5,"writeUrlPattern":null},"source":"scenarios/progression-support-refunds-resolution.json"},{"checkGroups":[{"checkGroupId":"return-refund-interaction","feature":{"actors":["owner","staff","admin"],"criteria":[{"id":"757a","steps":[{"actor":"owner","do":"reload","settleMs":0},{"actor":"owner","do":"ensureSignedIn","name":"return-refund-owner","readyTestid":"current-user","settleMs":0},{"actor":"owner","do":"click","ifAvailable":true,"testid":"catalog-link"},{"as":"757atotal","do":"dbRecordStock","item":"Keyboard"},{"as":"757aEast","do":"dbRecordStock","item":"Keyboard","warehouse":"East"},{"as":"757aWest","do":"dbRecordStock","item":"Keyboard","warehouse":"West"},{"actor":"admin","as":"757arevenue","do":"recordNumber","testid":"admin-revenue"},{"actor":"owner","do":"click","in":{"contains":"Keyboard","testid":"item-card"},"testid":"buy-now"},{"actor":"owner","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"owner","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"owner","do":"expect","ignoreCase":true,"in":{"contains":"Keyboard","testid":"order-item"},"testid":"order-status","value":"pending","within":10000},{"actor":"owner","as":"757apaid","do":"recordNumber","in":{"contains":"Keyboard","testid":"order-item"},"testid":"order-total"},{"action":"ship","actor":"staff","do":"callAction","from":"owner","input":{"attribute":"data-ship-input","contains":"Keyboard","testid":"order-item"},"namedAction":{"args":[0],"id":"ship","params":[{"in":"body","name":"orderId","wireType":"u64"}],"path":"/api/fulfilment/ship","reducer":"ship_order"},"settleMs":0},{"actor":"staff","do":"expectActionOutcome","outcome":"accepted"},{"actor":"owner","do":"expect","ignoreCase":true,"in":{"contains":"Keyboard","testid":"order-item"},"testid":"order-status","value":"shipped","within":10000},{"do":"dbExpectStock","item":"Keyboard","plus":-1,"relativeTo":"757atotal"},{"actor":"owner","do":"reload","settleMs":0},{"actor":"owner","do":"ensureSignedIn","name":"return-refund-owner","readyTestid":"current-user","settleMs":0},{"actor":"owner","do":"click","testid":"support-link"},{"actor":"owner","do":"fill","testid":"support-subject","text":"Return refund 757a"},{"actor":"owner","do":"fill","testid":"support-message","text":"Please refund this order."},{"actor":"owner","do":"click","testid":"support-submit"},{"actor":"owner","contains":"Return refund 757a","do":"expect","testid":"support-ticket","within":10000},{"actor":"owner","contains":"Keyboard","do":"click","in":{"contains":"Return refund 757a","testid":"support-ticket"},"testid":"support-order-option"},{"actor":"owner","do":"click","in":{"contains":"Return refund 757a","testid":"support-ticket"},"testid":"support-link-order"},{"actor":"owner","do":"expect","in":{"contains":"Return refund 757a","testid":"support-ticket"},"testid":"support-order","within":10000},{"action":"supportRefund","actor":"staff","do":"callAction","from":"owner","input":{"attribute":"data-refund-input","contains":"Return refund 757a","testid":"support-ticket"},"namedAction":{"args":[0],"id":"supportRefund","method":"POST","params":[{"in":"path","name":"caseId","placeholder":"{caseId}","wireType":"u64"}],"path":"/api/support/cases/{caseId}/refund","reducer":"support_refund"},"settleMs":0},{"actor":"staff","do":"expectActionOutcome","outcome":"accepted"},{"do":"dbExpectStock","item":"Keyboard","plus":-1,"relativeTo":"757atotal"},{"actor":"owner","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"owner","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"owner","do":"click","in":{"contains":"Keyboard","testid":"order-item"},"testid":"return-item"},{"actor":"owner","contains":"Keyboard","containsText":"returned","do":"expect","ignoreCase":true,"testid":"order-item","within":10000},{"actor":"owner","do":"freshClient"},{"actor":"owner-fresh","do":"signIn","name":"return-refund-owner"},{"actor":"owner-fresh","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"owner-fresh","do":"click","testid":"orders-toggle"},{"actor":"owner-fresh","contains":"Keyboard","containsText":"returned","do":"expect","ignoreCase":true,"testid":"order-item","within":10000},{"actor":"owner-fresh","do":"expectNumber","in":{"contains":"Keyboard","testid":"order-item"},"plus":0,"relativeTo":"757apaid","testid":"order-refund-total","within":10000},{"do":"dbExpectStock","item":"Keyboard","plus":0,"relativeTo":"757aEast","warehouse":"East"},{"do":"dbExpectStock","item":"Keyboard","plus":0,"relativeTo":"757aWest","warehouse":"West"},{"actor":"admin","do":"reload","settleMs":0},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","testid":"admin-link","unlessVisible":"admin-revenue"},{"actor":"admin","do":"expectNumber","plus":0,"relativeTo":"757arevenue","testid":"admin-revenue","within":10000}]},{"id":"757b","steps":[{"actor":"owner","do":"reload","settleMs":0},{"actor":"owner","do":"ensureSignedIn","name":"return-refund-owner","readyTestid":"current-user","settleMs":0},{"actor":"owner","do":"click","ifAvailable":true,"testid":"catalog-link"},{"as":"757btotal","do":"dbRecordStock","item":"Desk Lamp"},{"as":"757bEast","do":"dbRecordStock","item":"Desk Lamp","warehouse":"East"},{"as":"757bWest","do":"dbRecordStock","item":"Desk Lamp","warehouse":"West"},{"actor":"admin","as":"757brevenue","do":"recordNumber","testid":"admin-revenue"},{"actor":"owner","do":"click","in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"buy-now"},{"actor":"owner","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"owner","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"owner","do":"expect","ignoreCase":true,"in":{"contains":"Desk Lamp","testid":"order-item"},"testid":"order-status","value":"pending","within":10000},{"actor":"owner","as":"757bpaid","do":"recordNumber","in":{"contains":"Desk Lamp","testid":"order-item"},"testid":"order-total"},{"action":"ship","actor":"staff","do":"callAction","from":"owner","input":{"attribute":"data-ship-input","contains":"Desk Lamp","testid":"order-item"},"namedAction":{"args":[0],"id":"ship","params":[{"in":"body","name":"orderId","wireType":"u64"}],"path":"/api/fulfilment/ship","reducer":"ship_order"},"settleMs":0},{"actor":"staff","do":"expectActionOutcome","outcome":"accepted"},{"actor":"owner","do":"expect","ignoreCase":true,"in":{"contains":"Desk Lamp","testid":"order-item"},"testid":"order-status","value":"shipped","within":10000},{"do":"dbExpectStock","item":"Desk Lamp","plus":-1,"relativeTo":"757btotal"},{"actor":"owner","do":"reload","settleMs":0},{"actor":"owner","do":"ensureSignedIn","name":"return-refund-owner","readyTestid":"current-user","settleMs":0},{"actor":"owner","do":"click","testid":"support-link"},{"actor":"owner","do":"fill","testid":"support-subject","text":"Return refund 757b"},{"actor":"owner","do":"fill","testid":"support-message","text":"Please refund this order."},{"actor":"owner","do":"click","testid":"support-submit"},{"actor":"owner","contains":"Return refund 757b","do":"expect","testid":"support-ticket","within":10000},{"actor":"owner","contains":"Desk Lamp","do":"click","in":{"contains":"Return refund 757b","testid":"support-ticket"},"testid":"support-order-option"},{"actor":"owner","do":"click","in":{"contains":"Return refund 757b","testid":"support-ticket"},"testid":"support-link-order"},{"actor":"owner","do":"expect","in":{"contains":"Return refund 757b","testid":"support-ticket"},"testid":"support-order","within":10000},{"actor":"owner","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"owner","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"owner","do":"click","in":{"contains":"Desk Lamp","testid":"order-item"},"testid":"return-item"},{"actor":"owner","contains":"Desk Lamp","containsText":"returned","do":"expect","ignoreCase":true,"testid":"order-item","within":10000},{"action":"supportRefund","actor":"staff","do":"callAction","from":"owner","input":{"attribute":"data-refund-input","contains":"Return refund 757b","testid":"support-ticket"},"namedAction":{"args":[0],"id":"supportRefund","method":"POST","params":[{"in":"path","name":"caseId","placeholder":"{caseId}","wireType":"u64"}],"path":"/api/support/cases/{caseId}/refund","reducer":"support_refund"},"settleMs":0},{"actor":"staff","do":"expectActionOutcome","outcome":"accepted"},{"actor":"owner","do":"freshClient"},{"actor":"owner-fresh","do":"signIn","name":"return-refund-owner"},{"actor":"owner-fresh","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"owner-fresh","do":"click","testid":"orders-toggle"},{"actor":"owner-fresh","contains":"Desk Lamp","containsText":"returned","do":"expect","ignoreCase":true,"testid":"order-item","within":10000},{"actor":"owner-fresh","do":"expectNumber","in":{"contains":"Desk Lamp","testid":"order-item"},"plus":0,"relativeTo":"757bpaid","testid":"order-refund-total","within":10000},{"do":"dbExpectStock","item":"Desk Lamp","plus":0,"relativeTo":"757bEast","warehouse":"East"},{"do":"dbExpectStock","item":"Desk Lamp","plus":0,"relativeTo":"757bWest","warehouse":"West"},{"actor":"admin","do":"reload","settleMs":0},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","testid":"admin-link","unlessVisible":"admin-revenue"},{"actor":"admin","do":"expectNumber","plus":0,"relativeTo":"757brevenue","testid":"admin-revenue","within":10000}]}],"id":757,"setup":[{"actor":"owner","do":"signUp","name":"return-refund-owner"},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"staff","do":"click","testid":"staff-link","unlessVisible":"support-assignee"},{"actor":"staff","do":"click","ifAvailable":true,"testid":"support-queue-link","unlessVisible":"support-assignee"},{"actor":"admin","do":"click","testid":"admin-link"}]},"packId":"ecommerce.feature.split-tender-refunds","requiresFeatures":["ecommerce.l3.order-returns-features","ecommerce.progression.fulfilment-queue","ecommerce.progression.support-refunds"],"role":"feature","source":"scenarios/progression-support-return-interaction.json"}],"id":"selected-source-112","scenario":{"level":6,"writeUrlPattern":null},"source":"scenarios/progression-support-return-interaction.json"},{"checkGroups":[{"checkGroupId":"support-assignment","feature":{"actors":["visitor","staff"],"criteria":[{"id":"611a","steps":[{"actor":"staff","do":"fill","in":{"contains":"Missing item","testid":"support-ticket"},"testid":"support-assignee","text":"staff"},{"actor":"staff","do":"click","in":{"contains":"Missing item","testid":"support-ticket"},"settleMs":1500,"testid":"support-update"},{"actor":"staff","do":"reload","settleMs":2500},{"actor":"staff","do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026","readyTestid":"current-user"},{"actor":"staff","do":"click","ifAvailable":true,"testid":"staff-link","unlessVisible":"support-assignee"},{"actor":"staff","do":"click","ifAvailable":true,"testid":"support-queue-link","unlessVisible":"support-assignee"},{"actor":"staff","do":"expect","in":{"contains":"Missing item","testid":"support-ticket"},"testid":"support-assignee","value":"staff"}]}],"id":611,"setup":[{"actor":"visitor","do":"click","testid":"support-link"},{"actor":"visitor","do":"fill","testid":"support-email","text":"triage@example.com"},{"actor":"visitor","do":"fill","testid":"support-subject","text":"Missing item"},{"actor":"visitor","do":"fill","testid":"support-message","text":"One item is missing."},{"actor":"visitor","do":"click","testid":"support-submit"},{"actor":"visitor","do":"expect","nonEmpty":true,"testid":"support-reference"},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"staff","do":"click","testid":"staff-link","unlessVisible":"support-assignee"},{"actor":"staff","do":"click","ifAvailable":true,"testid":"support-queue-link","unlessVisible":"support-assignee"}]},"packId":"ecommerce.progression.support-triage","role":"feature","source":"scenarios/progression-support-triage.json"},{"checkGroupId":"support-priority","feature":{"actors":["visitor","staff"],"criteria":[{"id":"611b","steps":[{"actor":"staff","do":"fill","in":{"contains":"Missing item","testid":"support-ticket"},"testid":"support-priority","text":"high"},{"actor":"staff","do":"click","in":{"contains":"Missing item","testid":"support-ticket"},"settleMs":1500,"testid":"support-update"},{"actor":"staff","do":"reload","settleMs":2500},{"actor":"staff","do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026","readyTestid":"current-user"},{"actor":"staff","do":"click","ifAvailable":true,"testid":"staff-link","unlessVisible":"support-assignee"},{"actor":"staff","do":"click","ifAvailable":true,"testid":"support-queue-link","unlessVisible":"support-assignee"},{"actor":"staff","do":"expect","in":{"contains":"Missing item","testid":"support-ticket"},"testid":"support-priority","value":"high"}]}],"id":611,"setup":[{"actor":"visitor","do":"click","testid":"support-link"},{"actor":"visitor","do":"fill","testid":"support-email","text":"triage@example.com"},{"actor":"visitor","do":"fill","testid":"support-subject","text":"Missing item"},{"actor":"visitor","do":"fill","testid":"support-message","text":"One item is missing."},{"actor":"visitor","do":"click","testid":"support-submit"},{"actor":"visitor","do":"expect","nonEmpty":true,"testid":"support-reference"},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"staff","do":"click","testid":"staff-link","unlessVisible":"support-assignee"},{"actor":"staff","do":"click","ifAvailable":true,"testid":"support-queue-link","unlessVisible":"support-assignee"}]},"packId":"ecommerce.progression.support-triage","role":"feature","source":"scenarios/progression-support-triage.json"},{"checkGroupId":"support-status","feature":{"actors":["visitor","staff"],"criteria":[{"id":"611c","steps":[{"actor":"staff","do":"fill","in":{"contains":"Missing item","testid":"support-ticket"},"testid":"support-status-input","text":"in progress"},{"actor":"staff","do":"click","in":{"contains":"Missing item","testid":"support-ticket"},"settleMs":1500,"testid":"support-update"},{"actor":"staff","contains":"in progress","do":"expect","in":{"contains":"Missing item","testid":"support-ticket"},"testid":"support-status"}]}],"id":611,"setup":[{"actor":"visitor","do":"click","testid":"support-link"},{"actor":"visitor","do":"fill","testid":"support-email","text":"triage@example.com"},{"actor":"visitor","do":"fill","testid":"support-subject","text":"Missing item"},{"actor":"visitor","do":"fill","testid":"support-message","text":"One item is missing."},{"actor":"visitor","do":"click","testid":"support-submit"},{"actor":"visitor","do":"expect","nonEmpty":true,"testid":"support-reference"},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"staff","do":"click","testid":"staff-link","unlessVisible":"support-assignee"},{"actor":"staff","do":"click","ifAvailable":true,"testid":"support-queue-link","unlessVisible":"support-assignee"}]},"packId":"ecommerce.progression.support-triage","role":"feature","source":"scenarios/progression-support-triage.json"}],"id":"selected-source-113","scenario":{"level":2,"writeUrlPattern":null},"source":"scenarios/progression-support-triage.json"}],"fixture":{"accounts":[{"password":"stackbench-admin-2026","roles":["admin"],"username":"admin"},{"password":"stackbench-staff-2026","roles":["staff"],"username":"staff"}],"empty":["carts","orders","reviews","returns"],"items":[{"category":"Home","name":"Air Purifier","price":"189.00","stock":{"East":60,"West":40}},{"category":"Audio","name":"Bluetooth Speaker","price":"79.50","stock":{"East":50,"West":50}},{"category":"Home","name":"Coffee Grinder","price":"64.00","stock":{"East":70,"West":30}},{"category":"Home","name":"Desk Lamp","price":"42.00","stock":{"East":55,"West":45}},{"category":"Home","name":"Espresso Machine","price":"449.00","stock":{"East":80,"West":20}},{"category":"Computing","name":"Gaming Mouse","price":"59.00","stock":{"East":50,"West":50}},{"category":"Audio","name":"Headphones","price":"199.00","stock":{"East":60,"West":40}},{"category":"Home","name":"Induction Cooktop","price":"329.00","stock":{"East":50,"West":50}},{"category":"Computing","name":"Keyboard","price":"89.00","stock":{"East":70,"West":30}},{"category":"Computing","name":"Laptop Stand","price":"29.00","stock":{"East":90,"West":10}},{"category":"Photo","name":"Mirrorless Camera","price":"1299.00","stock":{"East":2,"West":1}},{"category":"Home","name":"USB Cable","price":"65.00","stock":{"East":0,"West":0}},{"category":"Computing","name":"Webcam","price":"69.00","stock":{"East":60,"West":40}}],"warehouses":["East","West"]},"packs":[{"actions":["click","expect","signIn","signUp","waitUntilAbsent"],"budget":{"maxRuntimeMs":18000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.feature.accounts","includeRoles":["feature"],"moduleType":"feature"},{"actions":["click","dbExpectStock","dbSetStock","expect","expectNumber","fill","signIn","signUp"],"budget":{"maxRuntimeMs":120000,"status":"bounded"},"capabilities":["browser","database-observation","direct-database-write"],"evidence":["browser-observation","database-observation"],"id":"ecommerce.feature.bundle-checkout","includeRoles":["feature"],"moduleType":"feature"},{"actions":["click","dbExpectStock","dbSetStock","expect","expectNumber","fill","signIn","signUp"],"budget":{"maxRuntimeMs":120000,"status":"bounded"},"capabilities":["browser","database-observation","direct-database-write"],"evidence":["browser-observation","database-observation"],"id":"ecommerce.feature.bundle-returns","includeRoles":["feature"],"moduleType":"feature"},{"actions":["click","expect","expectNumber","signUp","wait"],"budget":{"maxRuntimeMs":42000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.feature.cart","includeRoles":["feature"],"moduleType":"feature","stableId":"ecommerce.feature.cart-checkout"},{"actions":["expect","expectSequence","fill"],"budget":{"maxRuntimeMs":30000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.feature.catalog-discovery","includeRoles":["feature"],"moduleType":"feature","stableId":"ecommerce.feature.catalog"},{"actions":["expect","expectNumber"],"budget":{"maxRuntimeMs":30000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.feature.catalog-items","includeRoles":["feature"],"moduleType":"feature","stableId":"ecommerce.feature.catalog"},{"actions":["click","ensureSignedIn","expect","expectNumber","reload","signUp","wait"],"budget":{"maxRuntimeMs":42000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.feature.checkout","includeRoles":["feature"],"moduleType":"feature","stableId":"ecommerce.feature.cart-checkout"},{"actions":["click","expect","expectElementCount","expectNumber","fill","reload","signIn"],"budget":{"maxRuntimeMs":120000,"status":"bounded"},"capabilities":["browser","database-observation","direct-database-write"],"evidence":["browser-observation","database-observation"],"id":"ecommerce.feature.product-bundles","includeRoles":["feature"],"moduleType":"feature"},{"actions":["click","expect","expectNumber","signUp"],"budget":{"maxRuntimeMs":24000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.feature.purchasing","includeRoles":["feature"],"moduleType":"feature"},{"actions":["click","expect","fill","openItem","signUp"],"budget":{"maxRuntimeMs":22000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.feature.reviews","includeRoles":["feature"],"moduleType":"feature"},{"actions":["callAction","click","dbExpectStock","dbRecordStock","ensureSignedIn","expect","expectActionOutcome","expectElementCount","expectNumber","fill","freshClient","recordNumber","reload","signIn","signUp"],"budget":{"maxRuntimeMs":120000,"status":"bounded"},"capabilities":["browser","database-observation","direct-server-call"],"evidence":["browser-observation","database-observation","fresh-client-observation"],"id":"ecommerce.feature.split-tender-refunds","includeRoles":["feature"],"moduleType":"feature"},{"actions":["callAction","click","ensureSignedIn","expect","expectActionOutcome","expectElementCount","expectNumber","fill","freshClient","reload","signIn","signUp"],"budget":{"maxRuntimeMs":180000,"status":"bounded"},"capabilities":["browser","direct-server-call"],"evidence":["browser-observation","fresh-client-observation"],"id":"ecommerce.feature.store-credit","includeRoles":["feature"],"moduleType":"feature"},{"actions":["click","dbExpectStock","dbSetStock","expect","expectElementCount","expectNumber","expectSequence","fill","freshClient","signIn","signUp"],"budget":{"maxRuntimeMs":180000,"status":"bounded"},"capabilities":["browser","database-observation","direct-server-call"],"evidence":["browser-observation","database-observation","fresh-client-observation"],"id":"ecommerce.feature.subscriptions","includeRoles":["feature"],"moduleType":"feature"},{"actions":["callAction","click","ensureSignedIn","expect","expectActionOutcome","expectNumber","recordNumber","reload","signIn"],"budget":{"maxRuntimeMs":30000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.feature.warehouse-admin","includeRoles":["feature"],"moduleType":"feature"},{"actions":["click","dbSetStock","ensureSignedIn","expect","reload","signIn","signUp"],"budget":{"maxRuntimeMs":86000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.l2.inventory-dashboard","includeRoles":["feature"],"moduleType":"feature","stableId":"ecommerce.inventory-operations"},{"actions":["click","ensureSignedIn","expect","expectNumber","recordNumber","reload","signIn","signUp"],"budget":{"maxRuntimeMs":60000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.l2.order-cancellation-features","includeRoles":["feature"],"moduleType":"feature","stableId":"ecommerce.returns-pricing"},{"actions":["click","expectNumber","fill","signIn"],"budget":{"maxRuntimeMs":94000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.l2.price-history-features","includeRoles":["feature"],"moduleType":"feature","stableId":"ecommerce.returns-pricing"},{"actions":["click","expect","signUp","waitUntilAbsent"],"budget":{"maxRuntimeMs":86000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.l2.recommendations","includeRoles":["feature"],"moduleType":"feature","stableId":"ecommerce.inventory-operations"},{"actions":["click","ensureSignedIn","expect","expectNumber","recordNumber","reload","signIn","signUp"],"budget":{"maxRuntimeMs":86000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.l2.sales-dashboard","includeRoles":["feature"],"moduleType":"feature","stableId":"ecommerce.inventory-operations"},{"actions":["click","dbExpectStock","dbRecordStock","expect","expectNumber","fill","recordNumber","signIn"],"budget":{"maxRuntimeMs":86000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.l2.stock-transfers-features","includeRoles":["feature"],"moduleType":"feature","stableId":"ecommerce.inventory-operations"},{"actions":["click","closeClient","expect","expectNumber","openClient","recordNumber","reload","signUp","wait"],"budget":{"maxRuntimeMs":360000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.l3.cart-expiration-features","includeRoles":["feature"],"moduleType":"feature","stableId":"ecommerce.l3.cart-expiration"},{"actions":["callAction","click","expect","expectActionOutcome","expectReplayRejected","fill","replayAs","signIn","signUp"],"budget":{"maxRuntimeMs":60000,"status":"bounded"},"capabilities":["browser","direct-server-call","request-replay"],"evidence":["browser-observation","server-refusal","server-response"],"id":"ecommerce.l3.deferred-access-specifications","includeRoles":["guarantee"],"moduleType":"specification","stableId":"ecommerce.l3.deferred-access"},{"actions":["click","dbExpectStock","dbRecordStock","ensureSignedIn","expect","expectElapsed","expectNumber","fill","recordNumber","recordTime","reload","restartBackend","signIn","signUp","wait"],"budget":{"maxRuntimeMs":720000,"status":"bounded"},"capabilities":["backend-lifecycle","browser"],"evidence":["browser-observation","database-observation"],"id":"ecommerce.l3.deferred-durability-specifications","includeRoles":["guarantee"],"moduleType":"specification","stableId":"ecommerce.l3.deferred-durability"},{"actions":["click","dbExpectStock","dbRecordStock","ensureSignedIn","expect","expectElementCount","expectNumber","fill","recordNumber","reload","restartBackend","signIn","signUp","wait"],"budget":{"maxRuntimeMs":400000,"status":"bounded"},"capabilities":["backend-lifecycle","browser"],"evidence":["browser-observation","database-observation"],"id":"ecommerce.l3.deferred-integrity-specifications","includeRoles":["guarantee"],"moduleType":"specification","stableId":"ecommerce.l3.deferred-integrity"},{"actions":["click","ensureSignedIn","expect","reload","signIn","signUp","wait"],"budget":{"maxRuntimeMs":190000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.l3.order-delivery-features","includeRoles":["feature"],"moduleType":"feature","stableId":"ecommerce.l3.order-delivery"},{"actions":["callAction","click","dbExpectStock","dbRecordStock","ensureSignedIn","expect","expectActionOutcome","expectNumber","freshClient","recordNumber","reload","signIn","signUp"],"budget":{"maxRuntimeMs":120000,"status":"bounded"},"capabilities":["browser","database-observation"],"evidence":["browser-observation","database-observation","fresh-client-observation"],"id":"ecommerce.l3.order-returns-features","includeRoles":["feature"],"moduleType":"feature","stableId":"ecommerce.returns-pricing"},{"actions":["click","expect","expectNumber","recordNumber","signUp","wait"],"budget":{"maxRuntimeMs":300000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.l3.reservations-features","includeRoles":["feature"],"moduleType":"feature","stableId":"ecommerce.l3.reservations"},{"actions":["click","ensureSignedIn","expect","expectElementCount","expectNumber","fill","recordNumber","reload","signIn","wait"],"budget":{"maxRuntimeMs":150000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.l3.scheduled-restocks-features","includeRoles":["feature"],"moduleType":"feature","stableId":"ecommerce.l3.scheduled-restocks"},{"actions":["click","closeClient","dbExpectStock","dbRecordStock","ensureSignedIn","expect","expectElapsed","expectNumber","fill","recordNumber","recordTime","reload","restartBackend","signIn","signUp","wait"],"budget":{"maxRuntimeMs":300000,"status":"bounded"},"capabilities":["backend-lifecycle","browser"],"evidence":["browser-observation","database-observation"],"id":"ecommerce.l3.server-time-specifications","includeRoles":["guarantee"],"moduleType":"specification","stableId":"ecommerce.l3.server-time"},{"actions":["callAction","click","dbExpectStock","dbSetStock","ensureSignedIn","expect","expectActionOutcome","expectElementCount","fill","reload","signIn","signUp"],"budget":{"maxRuntimeMs":90000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.progression.automatic-reorder","includeRoles":["feature"],"moduleType":"feature"},{"actions":["callConcurrently","click","dbExpectCancellation","dbRecordCheckout","ensureSignedIn","expect","expectCallOutcomes","expectNumber","recordNumber","reload","signIn","signUp","wait"],"budget":{"maxRuntimeMs":24000,"status":"bounded"},"capabilities":["browser","concurrent-actors","direct-server-call"],"evidence":["browser-observation","concurrent-outcome","database-observation"],"id":"ecommerce.progression.cancellation-accounting-specifications","includeRoles":["guarantee"],"moduleType":"specification","stableId":"ecommerce.returns-pricing"},{"actions":["click","expect","signIn","signUp","waitUntilAbsent"],"budget":{"maxRuntimeMs":24000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.progression.cancellation-queue-specifications","includeRoles":["guarantee"],"moduleType":"specification","stableId":"ecommerce.returns-pricing"},{"actions":["click","dbSetStock","ensureSignedIn","expect","expectNumber","recordNumber","reload","signUp","wait"],"budget":{"maxRuntimeMs":350000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.progression.cart-recovery","includeRoles":["feature"],"moduleType":"feature"},{"actions":["click","expect","expectElementCount","fill","openItem","reload","signIn"],"budget":{"maxRuntimeMs":30000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.progression.catalog-management","includeRoles":["feature"],"moduleType":"feature"},{"actions":["click","expect","fill","signUp"],"budget":{"maxRuntimeMs":30000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.progression.customer-profile","includeRoles":["feature"],"moduleType":"feature"},{"actions":["callAction","click","ensureSignedIn","expect","expectActionOutcome","expectElapsed","expectElementCount","recordTime","reload","signIn","signUp","wait"],"budget":{"maxRuntimeMs":110000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.progression.delivery-notifications","includeRoles":["feature"],"moduleType":"feature"},{"actions":["click","dbSetStock","expect","expectElementCount","expectSequence","fill","reload","waitUntilAbsent"],"budget":{"maxRuntimeMs":141000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.progression.faceted-search","includeRoles":["feature"],"moduleType":"feature"},{"actions":["callAction","click","dbSetStock","ensureSignedIn","expect","expectActionOutcome","reload","signIn","signUp"],"budget":{"maxRuntimeMs":76000,"status":"bounded"},"capabilities":["browser","direct-server-call"],"evidence":["browser-observation","server-refusal"],"id":"ecommerce.progression.fulfilment-queue","includeRoles":["feature"],"moduleType":"feature","stableId":"ecommerce.operations-access"},{"actions":["callAction","click","dbExpectStock","dbRecordStock","ensureSignedIn","expect","expectActionOutcome","expectNumber","fill","freshClient","race","recordNumber","reload","signIn","signUp"],"budget":{"maxRuntimeMs":138000,"status":"bounded"},"capabilities":["browser","concurrent-actors","direct-server-call"],"evidence":["browser-observation","server-response"],"id":"ecommerce.progression.inventory-conservation-specifications","includeRoles":["guarantee"],"moduleType":"specification","stableId":"ecommerce.inventory-operations"},{"actions":["click","ensureSignedIn","expect","fill","reload","signIn","signUp"],"budget":{"maxRuntimeMs":55000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.progression.managed-support","includeRoles":["feature"],"moduleType":"feature"},{"actions":["click","expect","signUp"],"budget":{"maxRuntimeMs":40000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.progression.notification-preferences","includeRoles":["feature"],"moduleType":"feature"},{"actions":["callAction","click","dbExpectStock","dbRecordStock","ensureSignedIn","expect","expectActionOutcome","expectNumber","fill","recordNumber","reload","signIn","signUp"],"budget":{"maxRuntimeMs":98000,"status":"bounded"},"capabilities":["browser","direct-server-call","request-replay"],"evidence":["server-refusal","server-response"],"id":"ecommerce.progression.operations-access-specifications","includeRoles":["guarantee"],"moduleType":"specification","stableId":"ecommerce.operations-access"},{"actions":["click","expect","fill","signIn","signUp"],"budget":{"maxRuntimeMs":65000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.progression.order-support","includeRoles":["feature"],"moduleType":"feature"},{"actions":["callConcurrently","click","expect","expectCallOutcomes","expectElementCount","expectNumber","freshClient","recordNumber","signIn","signUp"],"budget":{"maxRuntimeMs":30000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.progression.payment-records","includeRoles":["feature"],"moduleType":"feature"},{"actions":["click","expect","expectNumber","expectSequence","signUp"],"budget":{"maxRuntimeMs":70000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.progression.personalized-recommendations","includeRoles":["feature"],"moduleType":"feature"},{"actions":["click","ensureSignedIn","expect","expectNumber","fill","pressKey","recordNumber","reload","signIn","signUp","wait"],"budget":{"maxRuntimeMs":24000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.progression.price-accounting-specifications","includeRoles":["guarantee"],"moduleType":"specification","stableId":"ecommerce.returns-pricing"},{"actions":["callAction","click","ensureSignedIn","expect","expectActionOutcome","expectNumber","fill","freshClient","recordNumber","reload","signIn","signUp"],"budget":{"maxRuntimeMs":94000,"status":"bounded"},"capabilities":["browser","direct-server-call"],"evidence":["browser-observation","fresh-client-observation"],"id":"ecommerce.progression.price-history-specifications","includeRoles":["guarantee"],"moduleType":"specification","stableId":"ecommerce.returns-pricing"},{"actions":["click","expect","expectNumber","fill","signIn","signUp"],"budget":{"maxRuntimeMs":55000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.progression.promotion-checkout","includeRoles":["feature"],"moduleType":"feature"},{"actions":["click","expectNumber","fill","signIn","signUp"],"budget":{"maxRuntimeMs":40000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.progression.promotion-reporting","includeRoles":["feature"],"moduleType":"feature"},{"actions":["click","expect","expectNumber","fill","signIn","signUp"],"budget":{"maxRuntimeMs":45000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.progression.promotion-rules","includeRoles":["feature"],"moduleType":"feature"},{"actions":["click","expect","signUp"],"budget":{"maxRuntimeMs":130000,"status":"bounded"},"capabilities":["backend-lifecycle","browser"],"evidence":["browser-observation","fresh-client-observation"],"id":"ecommerce.progression.recommendation-feedback","includeRoles":["feature"],"moduleType":"feature"},{"actions":["armScriptCanary","callAction","expect","expectActionOutcome","expectNoScriptExecution","freshClient","openItem","signIn","signUp","wait"],"budget":{"maxRuntimeMs":82000,"status":"bounded"},"capabilities":["browser","direct-server-call","request-replay"],"evidence":["browser-observation","fresh-client-observation","server-refusal","server-response"],"id":"ecommerce.progression.review-access-specifications","includeRoles":["guarantee"],"moduleType":"specification"},{"actions":["click","expect","signIn"],"budget":{"maxRuntimeMs":30000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.progression.staff-access","includeRoles":["feature"],"moduleType":"feature"},{"actions":["click","expect","fill","signIn"],"budget":{"maxRuntimeMs":30000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.progression.staff-activity","includeRoles":["feature"],"moduleType":"feature"},{"actions":["click","expect","fill","signIn"],"budget":{"maxRuntimeMs":30000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.progression.staff-roles","includeRoles":["feature"],"moduleType":"feature"},{"actions":["callAction","click","dbSetStock","ensureSignedIn","expect","expectActionOutcome","expectElementCount","freshClient","reload","signIn","signUp","wait"],"budget":{"maxRuntimeMs":60000,"status":"bounded"},"capabilities":["browser","direct-database-write"],"evidence":["browser-observation"],"id":"ecommerce.progression.stock-alerts","includeRoles":["feature"],"moduleType":"feature"},{"actions":["click","ensureSignedIn","expect","fill","reload","signUp"],"budget":{"maxRuntimeMs":50000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.progression.support-history","includeRoles":["feature"],"moduleType":"feature"},{"actions":["click","expect","fill"],"budget":{"maxRuntimeMs":30000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.progression.support-intake","includeRoles":["feature"],"moduleType":"feature"},{"actions":["click","expect","fill","signIn","signUp"],"budget":{"maxRuntimeMs":70000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.progression.support-refunds","includeRoles":["feature"],"moduleType":"feature"},{"actions":["click","ensureSignedIn","expect","fill","reload","signIn"],"budget":{"maxRuntimeMs":45000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.progression.support-triage","includeRoles":["feature"],"moduleType":"feature"},{"actions":["callAction","click","dbExpectStock","dbRecordStock","dbSetStock","ensureSignedIn","expect","expectActionOutcome","expectElapsed","expectElementCount","expectNotReceived","expectNumber","expectReceived","expectReplayCompleted","expectReplayRejected","expectSequence","fill","freshClient","openItem","recordNumber","recordTime","reload","replayAs","signIn","signUp","wait","waitUntilAbsent"],"budget":{"maxRuntimeMs":464000,"status":"bounded"},"capabilities":["backend-lifecycle","browser","direct-server-call","request-replay"],"evidence":["browser-observation","database-observation","fresh-client-observation","server-response"],"id":"ecommerce.spec.access-control","includeRoles":["guarantee"],"moduleType":"specification"},{"actions":["callAction","callConcurrently","click","dbExpectStock","dbSetStock","ensureSignedIn","expect","expectActionOutcome","expectActorsWith","expectCallOutcomes","expectNumber","fill","reload","restartBackend","signIn","signUp","wait"],"budget":{"maxRuntimeMs":480000,"status":"bounded"},"capabilities":["backend-lifecycle","browser","database-observation","direct-database-write","direct-server-call"],"evidence":["browser-observation","database-observation","fresh-client-observation"],"id":"ecommerce.spec.bundle-integrity","includeRoles":["guarantee"],"moduleType":"specification"},{"actions":["callAction","callConcurrently","click","clickConcurrently","dbExpectCheckout","dbExpectPurchases","dbExpectStock","dbRecordCheckout","dbRecordStock","dbSetStock","ensureSignedIn","expect","expectActionOutcome","expectActorsWith","expectAgreement","expectCallOutcomes","expectNumber","fill","race","recordNumber","reload","signIn","signUp","wait"],"budget":{"maxRuntimeMs":125000,"status":"bounded"},"capabilities":["browser","concurrent-actors","direct-server-call"],"evidence":["concurrent-outcome","database-observation"],"id":"ecommerce.spec.concurrency-safety","includeRoles":["guarantee"],"moduleType":"specification"},{"actions":["dbSetStock","expectNumber","reload","setOffline","startAppServer","stopAppServer"],"budget":{"maxRuntimeMs":105000,"status":"bounded"},"capabilities":["backend-lifecycle","browser","direct-database-write"],"evidence":["database-observation","fresh-client-observation"],"id":"ecommerce.spec.external-data-sync","includeRoles":["guarantee"],"moduleType":"specification"},{"actions":["callAction","click","dbExpectStock","dbRecordStock","dbSetStock","ensureSignedIn","expect","expectActionOutcome","expectAgreement","expectElementCount","expectNumber","expectSequence","fill","openItem","recordNumber","reload","signIn","signUp","waitUntilAbsent"],"budget":{"maxRuntimeMs":184000,"status":"bounded"},"capabilities":["browser","concurrent-actors"],"evidence":["browser-observation","fresh-client-observation"],"id":"ecommerce.spec.live-state","includeRoles":["guarantee"],"moduleType":"specification"},{"actions":["click","dbExpectStock","dbRecordStock","expectSequence","fill","reload","signUp"],"budget":{"maxRuntimeMs":60000,"status":"bounded"},"capabilities":["browser","database-observation"],"evidence":["browser-observation","database-observation"],"id":"ecommerce.spec.search-ordering","includeRoles":["guarantee"],"moduleType":"specification"},{"actions":["callAction","callConcurrently","click","ensureSignedIn","expect","expectActionOutcome","expectCallOutcomes","expectElementCount","expectNumber","fill","freshClient","reload","restartBackend","signIn","signUp"],"budget":{"maxRuntimeMs":300000,"status":"bounded"},"capabilities":["backend-lifecycle","browser","database-observation","direct-server-call"],"evidence":["browser-observation","database-observation","fresh-client-observation"],"id":"ecommerce.spec.split-tender-refunds","includeRoles":["guarantee"],"moduleType":"specification"},{"actions":["click","confirmCheckout","crashCheckout","dbExpectCheckout","dbRecordCheckout","ensureSignedIn","expect","expectCrashCheckout","expectNumber","fill","freshClient","reload","restartBackend","setOffline","signIn","signUp"],"budget":{"maxRuntimeMs":768000,"status":"bounded"},"capabilities":["backend-lifecycle","browser","database-read","process-crash"],"evidence":["browser-observation","fresh-client-observation"],"id":"ecommerce.spec.state-durability","includeRoles":["guarantee"],"moduleType":"specification"},{"actions":["callAction","callConcurrently","click","ensureSignedIn","expect","expectActionOutcome","expectCallOutcomes","expectElementCount","expectNumber","fill","freshClient","reload","restartBackend","signIn","signUp"],"budget":{"maxRuntimeMs":300000,"status":"bounded"},"capabilities":["backend-lifecycle","browser","database-observation","direct-server-call"],"evidence":["browser-observation","database-observation","fresh-client-observation"],"id":"ecommerce.spec.store-credit","includeRoles":["guarantee"],"moduleType":"specification"},{"actions":["callAction","click","dbExpectStock","dbRecordStock","dbSetStock","expect","expectActionOutcome","expectElementCount","expectNumber","expectSequence","fill","freshClient","recordNumber","restartBackend","signIn","signUp","wait"],"budget":{"maxRuntimeMs":480000,"status":"bounded"},"capabilities":["backend-lifecycle","browser","database-observation","direct-server-call"],"evidence":["browser-observation","database-observation","fresh-client-observation"],"id":"ecommerce.spec.subscriptions","includeRoles":["guarantee"],"moduleType":"specification"},{"actions":["callAction","callConcurrently","click","dbExpectStock","dbRecordStock","dbSetStock","ensureSignedIn","expect","expectActionOutcome","expectCallOutcomes","expectElementCount","expectNumber","expectReplayCompleted","fill","freshClient","openItem","recordNumber","reload","replayAs","signIn","signUp","wait"],"budget":{"maxRuntimeMs":100000,"status":"bounded"},"capabilities":["browser","database-observation","direct-server-call"],"evidence":["browser-observation","database-observation","server-response"],"id":"ecommerce.spec.transactional-integrity","includeRoles":["guarantee"],"moduleType":"specification"}],"runtime":{"actions":[{"args":[0,1],"id":"addToCart","path":"/api/cart","reducer":"add_to_cart"},{"args":[0],"id":"buy","path":"/api/items/00000000-0000-0000-0000-000000000000/buy","reducer":"buy_now"},{"args":[],"id":"checkout","path":"/api/checkout","reducer":"checkout"},{"args":[0,0,1],"id":"restock","path":"/api/admin/restock","reducer":"admin_restock"},{"args":["",""],"id":"signIn","path":"/api/auth/signin","reducer":"sign_in"},{"args":["",""],"id":"signUp","params":[{"in":"body","name":"username"},{"in":"body","name":"password"}],"path":"/api/auth/signup","reducer":"sign_up"}],"portOffset":300,"reseedOnReset":true,"restartProbe":"/api/items"},"schemaVersion":3,"task":{"baseExecutionSha256":null,"mode":"action"},"track":"ecommerce"}},"calibration":{"calibrationSchemaVersion":2,"controls":[],"equivalenceDecisions":[],"fixture":{"id":"ecommerce.operations","sourceSha256":"d06444b72dc94fe1ef5e08867d875e1f3bbaa5cd82c35a3558f399c1fcb5ceae"},"id":"ecommerce.dependency-l3-calibration","mutations":[{"backend":"mongodb","executionSha256":"7f2d78efab7c52336d532b6df47adc32b99e9e3f5b55f84254217e67ab5adf69","path":"grader/mutations/mongodb-ecommerce.json","referenceId":"ecommerce-reference-mongodb","sha256":"9424f03ba21307933ea4c7a81ee4f06bd80d659c1dfbe02938fa715167992f08","targets":[{"id":"active-search-uses-purchase-ranking","stableKeys":["ecommerce.spec.search-ordering.search-ordering.402b"]},{"id":"authorized-restock-does-not-change-stock","stableKeys":["ecommerce.feature.warehouse-admin.admin-write.103a"]},{"id":"cancel-does-not-restore-stock-feature","stableKeys":["ecommerce.returns-pricing.cancellation-and-return.3a"]},{"id":"cancel-does-not-restore-stock-fresh-client","stableKeys":["ecommerce.inventory-operations.stock-conservation.202b","ecommerce.inventory-operations.stock-conservation.202c"]},{"id":"cancel-restores-stock-but-keeps-pending-status","stableKeys":["ecommerce.returns-pricing.cancellation-and-return.3b"]},{"id":"cancellation-accounting-loses-stock-restoration","stableKeys":["ecommerce.returns-pricing.refund-accounting.203a"]},{"id":"cancelled-order-remains-in-revenue-feature","stableKeys":["ecommerce.returns-pricing.cancellation-and-return.3a"]},{"id":"cancelled-order-remains-in-revenue-invariant","stableKeys":["ecommerce.returns-pricing.refund-accounting.203a"]},{"id":"cancelled-restock-remains-pending","stableKeys":["ecommerce.l3.scheduled-restocks.scheduled-restocks.306a"]},{"id":"cart-add-uses-another-account-cart","stableKeys":["ecommerce.spec.access-control.cart-boundary.109a"]},{"id":"cart-hydration-loses-account-state","stableKeys":["ecommerce.spec.state-durability.account-state-recovery.105a"]},{"id":"cart-repeat-does-not-increment","stableKeys":["ecommerce.feature.cart-checkout.cart.4a"]},{"id":"catalog-initial-ranking-is-reversed","stableKeys":["ecommerce.feature.catalog.catalog-ranking.2b"]},{"id":"catalog-price-is-offset","stableKeys":["ecommerce.feature.catalog.catalog-values.2a"]},{"id":"catalog-product-name-is-not-published","stableKeys":["ecommerce.progression.catalog-management.catalog-management.622a","ecommerce.progression.catalog-management.catalog-management.622b"]},{"id":"catalog-search-requires-exact-name","stableKeys":["ecommerce.feature.catalog.catalog-search.2d"]},{"id":"catalog-variants-are-discarded","stableKeys":["ecommerce.progression.catalog-management.catalog-management.622b"]},{"id":"category-totals-skip-the-newest-order","stableKeys":["ecommerce.inventory-operations.operational-views.5f"]},{"id":"checkout-claim-is-not-atomic","stableKeys":["ecommerce.spec.concurrency-safety.duplicate-checkout.203b"]},{"id":"checkout-crash-durability","stableKeys":["ecommerce.spec.state-durability.checkout-crash-durability.910b"]},{"id":"checkout-crash-integrity","stableKeys":["ecommerce.spec.state-durability.checkout-crash-integrity.910a"]},{"id":"checkout-leaves-cart-claimed","stableKeys":["ecommerce.feature.cart-checkout.cart.4d"]},{"id":"completed-restock-is-replayed","stableKeys":["ecommerce.l3.deferred-integrity.exactly-once.311a"]},{"id":"concurrent-cart-add-does-not-increment","stableKeys":["ecommerce.spec.concurrency-safety.duplicate-checkout.203a"]},{"id":"customer-can-cancel-foreign-order-1-1","stableKeys":["ecommerce.operations-access.order-owner.204a"]},{"id":"customer-can-cancel-scheduled-restock","stableKeys":["ecommerce.l3.deferred-access.scheduled-work-access.317a"]},{"id":"customer-can-create-promotion","stableKeys":["ecommerce.spec.access-control.promotion-management-boundary.620b"]},{"id":"customer-can-ship-order-direct-1-1","stableKeys":["ecommerce.operations-access.operator-authorization.201c"]},{"id":"customer-signin-gains-staff-role","stableKeys":["ecommerce.spec.access-control.staff-area-boundary.601b"]},{"id":"direct-purchase-is-attributed-to-another-account","stableKeys":["ecommerce.spec.access-control.purchase-attribution.102a"]},{"id":"direct-purchase-total-ignores-store-price","stableKeys":["ecommerce.spec.transactional-integrity.server-price.104a"]},{"id":"direct-review-access-is-not-checked","stableKeys":["ecommerce.progression.review-access-specifications.review-eligibility-direct.618a"]},{"id":"due-restock-does-not-change-stock","stableKeys":["ecommerce.l3.scheduled-restocks.scheduled-restocks.305a"]},{"id":"duplicate-signup-reports-success","stableKeys":["ecommerce.feature.accounts.accounts.1b"]},{"id":"espresso-stock-row-ignores-live-updates","stableKeys":["ecommerce.spec.live-state.purchase-stock.3b"]},{"id":"external-stock-polling-disabled","stableKeys":["ecommerce.spec.external-data-sync.external-stock.901a"]},{"id":"faceted-search-ignores-category","stableKeys":["ecommerce.progression.faceted-search.faceted-search.401a"]},{"id":"initial-dashboard-load-omits-low-stock","stableKeys":["ecommerce.inventory-operations.operational-views.5e","ecommerce.spec.live-state.inventory-dashboard.5a"]},{"id":"last-unit-allows-negative-stock","stableKeys":["ecommerce.spec.concurrency-safety.last-unit.201a","ecommerce.spec.concurrency-safety.last-unit.201b","ecommerce.spec.concurrency-safety.last-unit.201c"]},{"id":"live-admin-updates-keep-stale-category-totals","stableKeys":["ecommerce.spec.live-state.sales-dashboard.5b"]},{"id":"live-review-average-uses-an-extra-divisor","stableKeys":["ecommerce.spec.live-state.rating.6c"]},{"id":"low-stock-boundary-excludes-ten-live","stableKeys":["ecommerce.spec.live-state.inventory-dashboard.5a"]},{"id":"managed-support-allows-another-customer","stableKeys":["ecommerce.spec.access-control.managed-support-privacy.613b"]},{"id":"managed-support-live-refresh-keeps-stale-tickets","stableKeys":["ecommerce.spec.live-state.managed-support.613a"]},{"id":"negative-cart-quantity-is-accepted","stableKeys":["ecommerce.spec.access-control.cart-boundary.109b"]},{"id":"notification-preference-is-not-owner-scoped","stableKeys":["ecommerce.spec.access-control.notification-preferences-privacy.630b"]},{"id":"notification-preference-is-not-saved","stableKeys":["ecommerce.progression.notification-preferences.notification-preferences.630c","ecommerce.spec.state-durability.notification-preferences-reload.630a"]},{"id":"notification-toggle-frozen-at-open","stableKeys":["ecommerce.progression.notification-preferences.notification-preferences.630c"]},{"id":"open-review-list-ignores-live-update","stableKeys":["ecommerce.spec.live-state.open-list.902a"]},{"id":"operator-authorization-allows-customer-transfer","stableKeys":["ecommerce.operations-access.operator-authorization.201a"]},{"id":"order-history-is-not-owner-scoped","stableKeys":["ecommerce.spec.access-control.order-ownership.106a"]},{"id":"overdraw-transfer-is-accepted","stableKeys":["ecommerce.spec.transactional-integrity.stock-transfer-overdraw.2c"]},{"id":"pagination-repeats-first-page","stableKeys":["ecommerce.progression.faceted-search.faceted-search.402a"]},{"id":"profile-data-is-lost-on-server-restart","stableKeys":["ecommerce.spec.state-durability.customer-profile-reload.620a"]},{"id":"profile-read-is-not-owner-scoped","stableKeys":["ecommerce.spec.access-control.customer-profile-privacy.620b"]},{"id":"profile-summary-frozen-at-open","stableKeys":["ecommerce.progression.customer-profile.customer-profile.620c"]},{"id":"progression-customer-sees-fulfilment-content","stableKeys":["ecommerce.spec.access-control.fulfilment-area-boundary.1d"]},{"id":"promotion-save-drops-bounded-values","stableKeys":["ecommerce.progression.promotion-rules.promotion-rule-values.620a"]},{"id":"purchase-counts-never-affect-ranking","stableKeys":["ecommerce.spec.live-state.ranking.2c"]},{"id":"purchase-does-not-reduce-warehouse-stock","stableKeys":["ecommerce.spec.transactional-integrity.books-balance.107b"]},{"id":"purchase-order-uses-zero-price","stableKeys":["ecommerce.feature.purchasing.purchase-order.3c"]},{"id":"purchase-read-write-loses-concurrent-stock","stableKeys":["ecommerce.spec.concurrency-safety.restock-race.202a"]},{"id":"purchased-review-ui-does-not-submit","stableKeys":["ecommerce.spec.access-control.review-eligibility.108b"]},{"id":"purchases-do-not-affect-best-sellers","stableKeys":["ecommerce.inventory-operations.operational-views.5d"]},{"id":"queue-ignores-live-fulfilment-updates","stableKeys":["ecommerce.spec.live-state.fulfilment-queue.1a"]},{"id":"queue-warehouse-reports-west","stableKeys":["ecommerce.operations-access.fulfilment-queue.1b"]},{"id":"recommendations-ignore-pending-purchases","stableKeys":["ecommerce.inventory-operations.operational-views.5c"]},{"id":"reconnect-generation-ignores-current-catalog","stableKeys":["ecommerce.spec.external-data-sync.external-stock.901d"]},{"id":"reconnect-hydration-loses-account-state","stableKeys":["ecommerce.spec.state-durability.account-state-recovery.105b"]},{"id":"reload-hydrates-an-empty-cart","stableKeys":["ecommerce.spec.state-durability.cart-reload.4b"]},{"id":"repeat-review-uses-a-new-owner-key","stableKeys":["ecommerce.spec.transactional-integrity.unique-review.6b"]},{"id":"restock-adds-the-wrong-quantity","stableKeys":["ecommerce.spec.live-state.warehouse-stock.7c"]},{"id":"restock-does-not-increase-stock","stableKeys":["ecommerce.spec.live-state.warehouse-stock.7c"]},{"id":"restock-race-records-wrong-order-total","stableKeys":["ecommerce.spec.concurrency-safety.restock-race.202a"]},{"id":"revenue-aggregation-ignores-order-totals","stableKeys":["ecommerce.spec.transactional-integrity.books-balance.107a"]},{"id":"review-comment-is-not-persisted","stableKeys":["ecommerce.feature.reviews.reviews.6a"]},{"id":"review-owner-deny-after-write","stableKeys":["ecommerce.progression.review-access-specifications.review-eligibility-direct.618a"]},{"id":"review-owner-reject-all","stableKeys":["ecommerce.progression.review-access-specifications.review-eligibility-direct.618a"]},{"id":"review-owner-trust-username","stableKeys":["ecommerce.progression.review-access-specifications.review-eligibility-direct.618a"]},{"id":"review-script-reject-all","stableKeys":["ecommerce.progression.review-access-specifications.stored-review-script.9180a"]},{"id":"review-script-unsafe-render","stableKeys":["ecommerce.progression.review-access-specifications.stored-review-script.9180a"]},{"id":"role-assignment-drops-role","stableKeys":["ecommerce.spec.state-durability.staff-role-reload.621a"]},{"id":"role-editor-snaps-back-to-stored-role","stableKeys":["ecommerce.progression.staff-roles.staff-roles.621c"]},{"id":"scheduled-restock-countdown-is-fixed","stableKeys":["ecommerce.l3.scheduled-restocks.scheduled-restocks.302a"]},{"id":"scheduled-restock-never-becomes-due-after-restart","stableKeys":["ecommerce.l3.deferred-durability.restart-survival.311a"]},{"id":"server-restart-disables-catalog-recovery","stableKeys":["ecommerce.spec.external-data-sync.external-stock.901c"]},{"id":"server-time-restock-never-completes","stableKeys":["ecommerce.l3.server-time.server-time.312a"]},{"id":"session-token-not-persisted","stableKeys":["ecommerce.spec.state-durability.session-reload.1e"]},{"id":"shared-cart-live-events-ignored","stableKeys":["ecommerce.spec.live-state.shared-cart.4c"]},{"id":"ship-acknowledges-without-changing-status","stableKeys":["ecommerce.operations-access.fulfilment-queue.1c"]},{"id":"shipping-counts-sale-twice","stableKeys":["ecommerce.inventory-operations.shipping-accounting.202e"]},{"id":"signed-out-visitor-purchase-is-accepted","stableKeys":["ecommerce.spec.access-control.signed-out-purchase.3a"]},{"id":"signin-skips-password-verification","stableKeys":["ecommerce.feature.accounts.accounts.1c"]},{"id":"signout-keeps-current-account","stableKeys":["ecommerce.feature.accounts.accounts.1d"]},{"id":"signup-does-not-expose-created-account","stableKeys":["ecommerce.feature.accounts.accounts.1a"]},{"id":"staff-admin-access-survives-role-removal","stableKeys":["ecommerce.spec.access-control.staff-role-revocation.621d"]},{"id":"staff-can-assign-roles","stableKeys":["ecommerce.spec.access-control.staff-role-boundary.621b","ecommerce.spec.access-control.staff-role-revocation.621d"]},{"id":"staff-can-see-admin-navigation","stableKeys":["ecommerce.spec.access-control.warehouse-area-boundary.7a"]},{"id":"staff-can-use-direct-restock","stableKeys":["ecommerce.spec.access-control.warehouse-write-boundary.103b"]},{"id":"staff-role-write-precedes-denial","stableKeys":["ecommerce.spec.access-control.staff-role-boundary.621b","ecommerce.spec.access-control.staff-role-revocation.621d"]},{"id":"staff-signin-loses-staff-role","stableKeys":["ecommerce.progression.staff-access.staff-access.601a"]},{"id":"stock-alert-delivery-is-suppressed","stableKeys":["ecommerce.progression.stock-alerts.stock-alert-delivery.631c"]},{"id":"stock-alert-repeats-while-in-stock","stableKeys":["ecommerce.spec.transactional-integrity.stock-alert-deduplication.631a"]},{"id":"stock-alerts-are-not-owner-scoped","stableKeys":["ecommerce.spec.access-control.stock-alert-privacy.631b"]},{"id":"support-history-is-lost-on-server-restart","stableKeys":["ecommerce.spec.state-durability.support-history-reload.612a"]},{"id":"support-history-is-not-owner-scoped","stableKeys":["ecommerce.spec.access-control.support-history-privacy.612b"]},{"id":"support-history-leaks-to-signed-out-visitors","stableKeys":["ecommerce.spec.access-control.support-history-logout.612d"]},{"id":"support-history-rows-are-hidden","stableKeys":["ecommerce.progression.support-history.support-history.612c","ecommerce.spec.access-control.support-history-logout.612d","ecommerce.spec.access-control.support-history-privacy.612b","ecommerce.spec.state-durability.support-history-reload.612a"]},{"id":"support-intake-returns-no-reference","stableKeys":["ecommerce.progression.support-intake.support-intake.610a"]},{"id":"support-replies-present-at-open-are-hidden","stableKeys":["ecommerce.progression.managed-support.managed-support.613c"]},{"id":"support-triage-discards-updates","stableKeys":["ecommerce.progression.support-triage.support-assignment.611a","ecommerce.progression.support-triage.support-priority.611b","ecommerce.progression.support-triage.support-status.611c"]},{"id":"transfer-creates-stock-during-race","stableKeys":["ecommerce.inventory-operations.stock-conservation.202d"]},{"id":"transfer-debits-source-without-crediting-existing-destination","stableKeys":["ecommerce.inventory-operations.stock-conservation.202a","ecommerce.inventory-operations.warehouse-transfer.2a","ecommerce.operations-access.operator-authorization.201a"]},{"id":"transfer-totals-omit-destination-credit-live","stableKeys":["ecommerce.spec.live-state.stock-transfers.2b"]},{"id":"unauthenticated-purchase-defaults-to-admin","stableKeys":["ecommerce.spec.access-control.purchase-session.101a"]},{"id":"unpurchased-review-is-accepted","stableKeys":["ecommerce.spec.access-control.review-eligibility.108a"]},{"id":"warehouse-view-omits-one-location","stableKeys":["ecommerce.feature.warehouse-admin.warehouse-view.7b"]}]},{"backend":"postgres","executionSha256":"000c81392cdd01dabc87082c7a8b7d669a7eb07beaa28c084f186f35890c2fe2","path":"grader/mutations/postgres-ecommerce.json","referenceId":"ecommerce-reference-postgres","sha256":"13ea2eba20da22e1f1712ccb03715158bf67ce0934672efdc94c31795fb0422a","targets":[{"id":"account-state-reload-discards-session","stableKeys":["ecommerce.spec.state-durability.account-state-recovery.105a"]},{"id":"active-search-uses-purchase-ranking","stableKeys":["ecommerce.spec.search-ordering.search-ordering.402b"]},{"id":"admin-sockets-do-not-join-admin-room","stableKeys":["ecommerce.spec.live-state.sales-dashboard.5b"]},{"id":"admin-state-change-is-not-broadcast","stableKeys":["ecommerce.spec.live-state.inventory-dashboard.5a"]},{"id":"admin-warehouse-view-drops-one-location","stableKeys":["ecommerce.feature.warehouse-admin.warehouse-view.7b"]},{"id":"authorized-restock-does-not-change-stock","stableKeys":["ecommerce.feature.warehouse-admin.admin-write.103a"]},{"id":"cancel-does-not-restore-stock-feature","stableKeys":["ecommerce.returns-pricing.cancellation-and-return.3a"]},{"id":"cancel-does-not-restore-stock-fresh-client","stableKeys":["ecommerce.inventory-operations.stock-conservation.202b","ecommerce.inventory-operations.stock-conservation.202c"]},{"id":"cancel-restores-stock-but-keeps-pending-status","stableKeys":["ecommerce.returns-pricing.cancellation-and-return.3b"]},{"id":"cancellation-accounting-loses-stock-restoration","stableKeys":["ecommerce.returns-pricing.refund-accounting.203a"]},{"id":"cart-update-accepts-negative-quantity","stableKeys":["ecommerce.spec.access-control.cart-boundary.109b"]},{"id":"category-totals-render-as-session-deltas","stableKeys":["ecommerce.inventory-operations.operational-views.5f"]},{"id":"checkout-crash-durability","stableKeys":["ecommerce.spec.state-durability.checkout-crash-durability.910b"]},{"id":"checkout-crash-integrity","stableKeys":["ecommerce.spec.state-durability.checkout-crash-integrity.910a"]},{"id":"correct-signin-is-refused","stableKeys":["ecommerce.feature.accounts.accounts.1d"]},{"id":"customer-can-cancel-foreign-order-1-1","stableKeys":["ecommerce.operations-access.order-owner.204a"]},{"id":"customer-can-ship-order-direct-1-1","stableKeys":["ecommerce.operations-access.operator-authorization.201c"]},{"id":"direct-purchase-is-attributed-to-previous-account","stableKeys":["ecommerce.spec.access-control.purchase-attribution.102a"]},{"id":"direct-purchase-order-total-is-offset","stableKeys":["ecommerce.feature.purchasing.purchase-order.3c"]},{"id":"direct-purchase-uses-constant-price","stableKeys":["ecommerce.spec.transactional-integrity.server-price.104a"]},{"id":"direct-review-access-is-not-checked","stableKeys":["ecommerce.progression.review-access-specifications.review-eligibility-direct.618a"]},{"id":"duplicate-signup-authenticates-existing-account","stableKeys":["ecommerce.feature.accounts.accounts.1b"]},{"id":"external-stock-polling-disabled","stableKeys":["ecommerce.spec.external-data-sync.external-stock.901a"]},{"id":"low-stock-threshold-is-two-units","stableKeys":["ecommerce.inventory-operations.operational-views.5e","ecommerce.spec.live-state.inventory-dashboard.5a"]},{"id":"notification-sync-flips-saved-toggle","stableKeys":["ecommerce.progression.notification-preferences.notification-preferences.630c"]},{"id":"offline-event-clears-account-state","stableKeys":["ecommerce.spec.state-durability.account-state-recovery.105b"]},{"id":"only-shipped-orders-earn-review-eligibility","stableKeys":["ecommerce.spec.access-control.review-eligibility.108a","ecommerce.spec.access-control.review-eligibility.108b"]},{"id":"open-review-list-ignores-live-update","stableKeys":["ecommerce.spec.live-state.open-list.902a"]},{"id":"open-review-list-renders-each-review-twice","stableKeys":["ecommerce.spec.live-state.open-list.902a"]},{"id":"operator-authorization-allows-customer-transfer","stableKeys":["ecommerce.operations-access.operator-authorization.201a"]},{"id":"oversell-no-row-lock","stableKeys":["ecommerce.spec.concurrency-safety.last-unit.201a","ecommerce.spec.concurrency-safety.last-unit.201b","ecommerce.spec.concurrency-safety.last-unit.201c"]},{"id":"password-verification-is-inverted","stableKeys":["ecommerce.feature.accounts.accounts.1c"]},{"id":"profile-summary-ignores-saved-address","stableKeys":["ecommerce.progression.customer-profile.customer-profile.620c"]},{"id":"progression-cancelled-orders-remain-in-revenue","stableKeys":["ecommerce.returns-pricing.refund-accounting.203a"]},{"id":"progression-cancelled-restock-still-runs","stableKeys":["ecommerce.l3.scheduled-restocks.scheduled-restocks.306a"]},{"id":"progression-cart-add-uses-another-account","stableKeys":["ecommerce.spec.access-control.cart-boundary.109a"]},{"id":"progression-cart-line-does-not-increment","stableKeys":["ecommerce.feature.cart-checkout.cart.4a"]},{"id":"progression-cart-update-uses-wrong-room","stableKeys":["ecommerce.spec.live-state.shared-cart.4c"]},{"id":"progression-catalog-price-is-offset","stableKeys":["ecommerce.feature.catalog.catalog-values.2a"]},{"id":"progression-catalog-product-name-is-not-published","stableKeys":["ecommerce.progression.catalog-management.catalog-management.622a","ecommerce.progression.catalog-management.catalog-management.622b"]},{"id":"progression-catalog-ranking-is-reversed","stableKeys":["ecommerce.feature.catalog.catalog-ranking.2b"]},{"id":"progression-catalog-search-requires-exact-name","stableKeys":["ecommerce.feature.catalog.catalog-search.2d"]},{"id":"progression-catalog-variants-are-discarded","stableKeys":["ecommerce.progression.catalog-management.catalog-management.622b"]},{"id":"progression-checkout-leaves-cart-lines","stableKeys":["ecommerce.feature.cart-checkout.cart.4d"]},{"id":"progression-concurrent-cart-line-does-not-increment","stableKeys":["ecommerce.spec.concurrency-safety.duplicate-checkout.203a"]},{"id":"progression-concurrent-checkout-leaves-cart-lines","stableKeys":["ecommerce.spec.concurrency-safety.duplicate-checkout.203b"]},{"id":"progression-customer-can-create-promotions","stableKeys":["ecommerce.spec.access-control.promotion-management-boundary.620b"]},{"id":"progression-customer-sees-fulfilment-content","stableKeys":["ecommerce.spec.access-control.fulfilment-area-boundary.1d"]},{"id":"progression-customer-sees-staff-tools","stableKeys":["ecommerce.spec.access-control.staff-area-boundary.601b"]},{"id":"progression-customers-can-manage-scheduled-work","stableKeys":["ecommerce.l3.deferred-access.scheduled-work-access.317a"]},{"id":"progression-due-restock-does-not-run","stableKeys":["ecommerce.l3.scheduled-restocks.scheduled-restocks.305a"]},{"id":"progression-faceted-filter-ignores-category","stableKeys":["ecommerce.progression.faceted-search.faceted-search.401a"]},{"id":"progression-managed-support-is-not-shared","stableKeys":["ecommerce.spec.live-state.managed-support.613a"]},{"id":"progression-managed-support-leaks","stableKeys":["ecommerce.spec.access-control.managed-support-privacy.613b"]},{"id":"progression-notification-preferences-do-not-save","stableKeys":["ecommerce.spec.state-durability.notification-preferences-reload.630a"]},{"id":"progression-notifications-leak-across-accounts","stableKeys":["ecommerce.spec.access-control.notification-preferences-privacy.630b"]},{"id":"progression-order-history-ignores-owner","stableKeys":["ecommerce.spec.access-control.order-ownership.106a"]},{"id":"progression-pagination-always-shows-first-page","stableKeys":["ecommerce.progression.faceted-search.faceted-search.402a"]},{"id":"progression-profile-address-is-discarded","stableKeys":["ecommerce.spec.state-durability.customer-profile-reload.620a"]},{"id":"progression-profile-reads-another-account","stableKeys":["ecommerce.spec.access-control.customer-profile-privacy.620b"]},{"id":"progression-promotion-discount-is-offset","stableKeys":["ecommerce.progression.promotion-rules.promotion-rule-values.620a"]},{"id":"progression-restart-timer-never-runs","stableKeys":["ecommerce.l3.server-time.server-time.312a"]},{"id":"progression-restock-adds-wrong-quantity","stableKeys":["ecommerce.spec.live-state.warehouse-stock.7c"]},{"id":"progression-restock-can-apply-more-than-once","stableKeys":["ecommerce.l3.deferred-integrity.exactly-once.311a"]},{"id":"progression-restock-countdown-is-fixed","stableKeys":["ecommerce.l3.scheduled-restocks.scheduled-restocks.302a"]},{"id":"progression-restock-does-not-survive-restart","stableKeys":["ecommerce.l3.deferred-durability.restart-survival.311a"]},{"id":"progression-revenue-double-counts-orders","stableKeys":["ecommerce.spec.transactional-integrity.books-balance.107a"]},{"id":"progression-review-conflict-is-not-updated","stableKeys":["ecommerce.spec.transactional-integrity.unique-review.6b"]},{"id":"progression-shipping-keeps-order-pending","stableKeys":["ecommerce.operations-access.fulfilment-queue.1c"]},{"id":"progression-staff-can-assign-roles","stableKeys":["ecommerce.spec.access-control.staff-role-boundary.621b","ecommerce.spec.access-control.staff-role-revocation.621d"]},{"id":"progression-staff-can-restock-directly","stableKeys":["ecommerce.spec.access-control.warehouse-write-boundary.103b"]},{"id":"progression-staff-role-is-lost-on-restart","stableKeys":["ecommerce.spec.state-durability.staff-role-reload.621a"]},{"id":"progression-staff-sees-admin-navigation","stableKeys":["ecommerce.spec.access-control.warehouse-area-boundary.7a"]},{"id":"progression-staff-tools-are-hidden","stableKeys":["ecommerce.progression.staff-access.staff-access.601a"]},{"id":"progression-stock-alerts-leak-across-accounts","stableKeys":["ecommerce.spec.access-control.stock-alert-privacy.631b"]},{"id":"progression-support-history-anonymous-leak","stableKeys":["ecommerce.spec.access-control.support-history-logout.612d"]},{"id":"progression-support-history-is-not-persisted","stableKeys":["ecommerce.spec.state-durability.support-history-reload.612a"]},{"id":"progression-support-history-leaks","stableKeys":["ecommerce.spec.access-control.support-history-privacy.612b"]},{"id":"progression-support-intake-is-disabled","stableKeys":["ecommerce.progression.support-intake.support-intake.610a"]},{"id":"progression-support-triage-update-is-disabled","stableKeys":["ecommerce.progression.support-triage.support-assignment.611a","ecommerce.progression.support-triage.support-priority.611b","ecommerce.progression.support-triage.support-status.611c"]},{"id":"purchase-does-not-broadcast-fulfilment-queue","stableKeys":["ecommerce.spec.live-state.fulfilment-queue.1a"]},{"id":"purchase-does-not-broadcast-ranking","stableKeys":["ecommerce.spec.live-state.ranking.2c"]},{"id":"purchase-does-not-decrement-warehouse-stock","stableKeys":["ecommerce.spec.transactional-integrity.books-balance.107b"]},{"id":"purchase-read-write-loses-concurrent-stock","stableKeys":["ecommerce.spec.concurrency-safety.restock-race.202a"]},{"id":"purchase-stock-change-is-not-broadcast--01-buying","stableKeys":["ecommerce.spec.live-state.purchase-stock.3b"]},{"id":"purchases-do-not-affect-best-sellers","stableKeys":["ecommerce.inventory-operations.operational-views.5d"]},{"id":"queue-warehouse-reports-west","stableKeys":["ecommerce.operations-access.fulfilment-queue.1b"]},{"id":"recommendations-ignore-pending-purchases","stableKeys":["ecommerce.inventory-operations.operational-views.5c"]},{"id":"reconnect-does-not-send-current-catalog","stableKeys":["ecommerce.spec.external-data-sync.external-stock.901d"]},{"id":"reload-discards-session-identity","stableKeys":["ecommerce.spec.state-durability.session-reload.1e"]},{"id":"reload-hydrates-an-empty-cart","stableKeys":["ecommerce.spec.state-durability.cart-reload.4b"]},{"id":"restock-overwrites-instead-of-increments","stableKeys":["ecommerce.spec.live-state.warehouse-stock.7c"]},{"id":"restock-race-records-wrong-order-total","stableKeys":["ecommerce.spec.concurrency-safety.restock-race.202a"]},{"id":"review-average-update-is-not-broadcast","stableKeys":["ecommerce.spec.live-state.rating.6c"]},{"id":"review-owner-deny-after-write","stableKeys":["ecommerce.progression.review-access-specifications.review-eligibility-direct.618a"]},{"id":"review-owner-reject-all","stableKeys":["ecommerce.progression.review-access-specifications.review-eligibility-direct.618a"]},{"id":"review-owner-trust-username","stableKeys":["ecommerce.progression.review-access-specifications.review-eligibility-direct.618a"]},{"id":"review-route-skips-purchase-eligibility","stableKeys":["ecommerce.spec.access-control.review-eligibility.108a"]},{"id":"review-script-reject-all","stableKeys":["ecommerce.progression.review-access-specifications.stored-review-script.9180a"]},{"id":"review-script-unsafe-render","stableKeys":["ecommerce.progression.review-access-specifications.stored-review-script.9180a"]},{"id":"server-restart-does-not-resynchronize-catalog","stableKeys":["ecommerce.spec.external-data-sync.external-stock.901c"]},{"id":"shipping-counts-sale-twice","stableKeys":["ecommerce.inventory-operations.shipping-accounting.202e"]},{"id":"signed-out-purchase-uses-default-account","stableKeys":["ecommerce.spec.access-control.signed-out-purchase.3a"]},{"id":"signed-out-visitors-do-not-see-reviews","stableKeys":["ecommerce.feature.reviews.reviews.6a"]},{"id":"signup-ui-does-not-enter-created-account","stableKeys":["ecommerce.feature.accounts.accounts.1a"]},{"id":"staff-admin-access-survives-role-removal","stableKeys":["ecommerce.spec.access-control.staff-role-revocation.621d"]},{"id":"staff-role-form-reverts-after-save","stableKeys":["ecommerce.progression.staff-roles.staff-roles.621c"]},{"id":"staff-role-write-precedes-denial","stableKeys":["ecommerce.spec.access-control.staff-role-boundary.621b","ecommerce.spec.access-control.staff-role-revocation.621d"]},{"id":"stock-alert-delivery-is-suppressed","stableKeys":["ecommerce.progression.stock-alerts.stock-alert-delivery.631c"]},{"id":"stock-alert-is-sent-after-every-restock","stableKeys":["ecommerce.spec.transactional-integrity.stock-alert-deduplication.631a"]},{"id":"support-first-reply-is-hidden","stableKeys":["ecommerce.progression.managed-support.managed-support.613c"]},{"id":"support-history-rows-are-hidden","stableKeys":["ecommerce.progression.support-history.support-history.612c","ecommerce.spec.access-control.support-history-logout.612d","ecommerce.spec.access-control.support-history-privacy.612b","ecommerce.spec.state-durability.support-history-reload.612a"]},{"id":"transfer-debits-source-without-crediting-existing-destination","stableKeys":["ecommerce.inventory-operations.stock-conservation.202a","ecommerce.inventory-operations.warehouse-transfer.2a","ecommerce.operations-access.operator-authorization.201a"]},{"id":"transfer-does-not-publish-warehouse-totals","stableKeys":["ecommerce.spec.live-state.stock-transfers.2b"]},{"id":"transfer-overdraft-guard-skips-bulk-transfers","stableKeys":["ecommerce.spec.transactional-integrity.stock-transfer-overdraw.2c"]},{"id":"transfer-overwrites-concurrent-purchase-with-stale-stock","stableKeys":["ecommerce.inventory-operations.stock-conservation.202d"]},{"id":"unauthenticated-direct-purchase-uses-default-account","stableKeys":["ecommerce.spec.access-control.purchase-session.101a"]}]},{"backend":"spacetime","executionSha256":"188b4c9a4373e4023f9e4a0add511232ac2afedb3283027544c6eff720ba05e8","path":"grader/mutations/spacetime-ecommerce.json","referenceId":"ecommerce-reference-spacetime","sha256":"302f43126a2a09f42a3a24d326f66c0928467b9cd27ccd9ae606908c8a1b0489","targets":[{"id":"account-state-token-is-not-restored-after-reload","stableKeys":["ecommerce.spec.state-durability.account-state-recovery.105a"]},{"id":"active-search-uses-purchase-ranking","stableKeys":["ecommerce.spec.search-ordering.search-ordering.402b"]},{"id":"admin-restock-preserves-existing-stock","stableKeys":["ecommerce.spec.live-state.warehouse-stock.7c"]},{"id":"admin-revenue-double-counts-every-order","stableKeys":["ecommerce.spec.transactional-integrity.books-balance.107a"]},{"id":"admin-total-stock-is-not-rendered","stableKeys":["ecommerce.spec.live-state.warehouse-stock.7c"]},{"id":"administrator-role-assignment-is-discarded","stableKeys":["ecommerce.spec.state-durability.staff-role-reload.621a"]},{"id":"authorized-restock-does-not-change-stock","stableKeys":["ecommerce.feature.warehouse-admin.admin-write.103a"]},{"id":"buy-now-creates-orders-without-reserving-stock--01-buying","stableKeys":["ecommerce.spec.live-state.purchase-stock.3b"]},{"id":"buy-now-records-the-wrong-order-total","stableKeys":["ecommerce.feature.purchasing.purchase-order.3c"]},{"id":"cancel-does-not-restore-stock-feature","stableKeys":["ecommerce.returns-pricing.cancellation-and-return.3a"]},{"id":"cancel-does-not-restore-stock-fresh-client","stableKeys":["ecommerce.inventory-operations.stock-conservation.202b","ecommerce.inventory-operations.stock-conservation.202c"]},{"id":"cancel-restores-stock-but-keeps-pending-status","stableKeys":["ecommerce.returns-pricing.cancellation-and-return.3b"]},{"id":"cancellation-accounting-loses-stock-restoration","stableKeys":["ecommerce.returns-pricing.refund-accounting.203a"]},{"id":"cancelled-order-remains-in-revenue-feature","stableKeys":["ecommerce.returns-pricing.cancellation-and-return.3a"]},{"id":"cancelled-order-remains-in-revenue-invariant","stableKeys":["ecommerce.returns-pricing.refund-accounting.203a"]},{"id":"cancelled-restock-remains-pending","stableKeys":["ecommerce.l3.scheduled-restocks.scheduled-restocks.306a"]},{"id":"cart-is-deleted-when-owner-disconnects","stableKeys":["ecommerce.spec.state-durability.cart-reload.4b"]},{"id":"cart-line-lookup-ignores-cart-ownership","stableKeys":["ecommerce.spec.access-control.cart-boundary.109a"]},{"id":"catalog-product-is-not-published","stableKeys":["ecommerce.progression.catalog-management.catalog-management.622a","ecommerce.progression.catalog-management.catalog-management.622b"]},{"id":"catalog-search-ignores-the-query","stableKeys":["ecommerce.feature.catalog.catalog-search.2d"]},{"id":"catalog-seeds-the-wrong-air-purifier-price","stableKeys":["ecommerce.feature.catalog.catalog-values.2a"]},{"id":"catalog-tie-breaks-in-reverse-alphabetical-order--01-catalog-ranking","stableKeys":["ecommerce.feature.catalog.catalog-ranking.2b"]},{"id":"catalog-tie-breaks-in-reverse-alphabetical-order--01-core","stableKeys":["ecommerce.spec.live-state.ranking.2c"]},{"id":"catalog-variants-are-discarded","stableKeys":["ecommerce.progression.catalog-management.catalog-management.622b"]},{"id":"category-totals-are-frozen-at-page-load","stableKeys":["ecommerce.spec.live-state.sales-dashboard.5b"]},{"id":"category-totals-count-only-since-the-dashboard-opened","stableKeys":["ecommerce.inventory-operations.operational-views.5f"]},{"id":"checkout-crash-durability","stableKeys":["ecommerce.spec.state-durability.checkout-crash-durability.910b"]},{"id":"checkout-crash-integrity","stableKeys":["ecommerce.spec.state-durability.checkout-crash-integrity.910a"]},{"id":"checkout-does-not-empty-cart","stableKeys":["ecommerce.spec.concurrency-safety.duplicate-checkout.203b"]},{"id":"checkout-does-not-empty-the-basic-cart","stableKeys":["ecommerce.feature.cart-checkout.cart.4d"]},{"id":"completed-restock-remains-pending","stableKeys":["ecommerce.l3.deferred-integrity.exactly-once.311a"]},{"id":"customer-can-cancel-foreign-order-1-1","stableKeys":["ecommerce.operations-access.order-owner.204a"]},{"id":"customer-can-ship-order-direct-1-1","stableKeys":["ecommerce.operations-access.operator-authorization.201c"]},{"id":"customer-profile-view-leaks-another-account","stableKeys":["ecommerce.spec.access-control.customer-profile-privacy.620b"]},{"id":"customers-can-create-promotions","stableKeys":["ecommerce.spec.access-control.promotion-management-boundary.620b"]},{"id":"customers-can-open-staff-tools","stableKeys":["ecommerce.spec.access-control.staff-area-boundary.601b"]},{"id":"customers-can-schedule-restocks","stableKeys":["ecommerce.l3.deferred-access.scheduled-work-access.317a"]},{"id":"direct-purchase-ignores-the-stored-price","stableKeys":["ecommerce.spec.transactional-integrity.server-price.104a"]},{"id":"direct-purchases-are-attributed-to-the-system-account","stableKeys":["ecommerce.spec.access-control.purchase-attribution.102a"]},{"id":"direct-restock-does-not-require-an-admin","stableKeys":["ecommerce.spec.access-control.warehouse-write-boundary.103b"]},{"id":"direct-review-access-is-not-checked","stableKeys":["ecommerce.progression.review-access-specifications.review-eligibility-direct.618a"]},{"id":"due-restock-omits-ledger-entry","stableKeys":["ecommerce.l3.scheduled-restocks.scheduled-restocks.305a"]},{"id":"duplicate-signup-is-silently-ignored","stableKeys":["ecommerce.feature.accounts.accounts.1b"]},{"id":"eligible-review-is-accepted-without-being-stored","stableKeys":["ecommerce.spec.access-control.review-eligibility.108a","ecommerce.spec.access-control.review-eligibility.108b"]},{"id":"every-signed-in-customer-is-treated-as-an-admin","stableKeys":["ecommerce.spec.access-control.warehouse-area-boundary.7a"]},{"id":"existing-cart-line-does-not-increment","stableKeys":["ecommerce.spec.concurrency-safety.duplicate-checkout.203a"]},{"id":"existing-cart-line-does-not-increment-basic-cart","stableKeys":["ecommerce.feature.cart-checkout.cart.4a"]},{"id":"faceted-search-ignores-category","stableKeys":["ecommerce.progression.faceted-search.faceted-search.401a"]},{"id":"faceted-search-next-page-does-not-advance","stableKeys":["ecommerce.progression.faceted-search.faceted-search.402a"]},{"id":"fulfilment-queue-is-frozen-at-page-load","stableKeys":["ecommerce.spec.live-state.fulfilment-queue.1a"]},{"id":"guest-purchase-falls-back-to-the-admin-account","stableKeys":["ecommerce.spec.access-control.purchase-session.101a"]},{"id":"low-stock-list-is-frozen-at-page-load","stableKeys":["ecommerce.spec.live-state.inventory-dashboard.5a"]},{"id":"low-stock-threshold-is-two-units","stableKeys":["ecommerce.inventory-operations.operational-views.5e","ecommerce.spec.live-state.inventory-dashboard.5a"]},{"id":"managed-support-leaks-and-accepts-cross-account-replies","stableKeys":["ecommerce.spec.access-control.managed-support-privacy.613b"]},{"id":"managed-support-live-replies-stay-at-initial-snapshot","stableKeys":["ecommerce.spec.live-state.managed-support.613a"]},{"id":"managed-support-replies-are-empty","stableKeys":["ecommerce.progression.managed-support.managed-support.613c","ecommerce.spec.live-state.managed-support.613a"]},{"id":"new-review-is-accepted-without-being-stored","stableKeys":["ecommerce.feature.reviews.reviews.6a"]},{"id":"nonpositive-cart-quantity-is-treated-as-removal","stableKeys":["ecommerce.spec.access-control.cart-boundary.109b"]},{"id":"notification-preferences-are-not-saved","stableKeys":["ecommerce.spec.state-durability.notification-preferences-reload.630a"]},{"id":"notification-preferences-leak-across-accounts","stableKeys":["ecommerce.spec.access-control.notification-preferences-privacy.630b"]},{"id":"open-review-list-renders-each-review-twice","stableKeys":["ecommerce.spec.live-state.open-list.902a"]},{"id":"open-review-list-snapshots-on-selection","stableKeys":["ecommerce.spec.live-state.open-list.902a"]},{"id":"operator-authorization-allows-customer-shipping","stableKeys":["ecommerce.operations-access.operator-authorization.201c"]},{"id":"operator-authorization-allows-customer-transfer","stableKeys":["ecommerce.operations-access.operator-authorization.201a"]},{"id":"order-views-return-every-customers-orders","stableKeys":["ecommerce.spec.access-control.order-ownership.106a"]},{"id":"pending-restock-timer-is-static","stableKeys":["ecommerce.l3.scheduled-restocks.scheduled-restocks.302a"]},{"id":"profile-is-lost-on-fresh-account-login","stableKeys":["ecommerce.spec.state-durability.customer-profile-reload.620a"]},{"id":"profile-summary-ignores-a-profile-saved-this-session","stableKeys":["ecommerce.progression.customer-profile.customer-profile.620c"]},{"id":"progression-customer-sees-fulfilment-content","stableKeys":["ecommerce.spec.access-control.fulfilment-area-boundary.1d"]},{"id":"promotion-rule-stores-the-wrong-discount","stableKeys":["ecommerce.progression.promotion-rules.promotion-rule-values.620a"]},{"id":"purchase-does-not-reserve-stock-last-unit","stableKeys":["ecommerce.spec.concurrency-safety.last-unit.201a","ecommerce.spec.concurrency-safety.last-unit.201b","ecommerce.spec.concurrency-safety.last-unit.201c"]},{"id":"purchase-does-not-update-ranking-count","stableKeys":["ecommerce.spec.live-state.ranking.2c"]},{"id":"purchases-do-not-affect-best-sellers","stableKeys":["ecommerce.inventory-operations.operational-views.5d"]},{"id":"purchases-do-not-leave-the-warehouses","stableKeys":["ecommerce.spec.transactional-integrity.books-balance.107b"]},{"id":"queue-warehouse-reports-west","stableKeys":["ecommerce.operations-access.fulfilment-queue.1b"]},{"id":"recommendations-ignore-pending-purchases","stableKeys":["ecommerce.inventory-operations.operational-views.5c"]},{"id":"reconnect-discards-the-visible-account-state","stableKeys":["ecommerce.spec.state-durability.account-state-recovery.105b"]},{"id":"repeat-review-inserts-a-second-row","stableKeys":["ecommerce.spec.transactional-integrity.unique-review.6b"]},{"id":"restart-restock-runs-early","stableKeys":["ecommerce.l3.server-time.server-time.312a"]},{"id":"restock-client-snapshot-overwrites-concurrent-purchases","stableKeys":["ecommerce.spec.concurrency-safety.restock-race.202a"]},{"id":"restock-race-records-wrong-order-total","stableKeys":["ecommerce.spec.concurrency-safety.restock-race.202a"]},{"id":"review-average-counts-rows-instead-of-ratings","stableKeys":["ecommerce.spec.live-state.rating.6c"]},{"id":"review-owner-reject-all","stableKeys":["ecommerce.progression.review-access-specifications.review-eligibility-direct.618a"]},{"id":"review-purchase-eligibility-is-not-checked","stableKeys":["ecommerce.spec.access-control.review-eligibility.108a"]},{"id":"review-script-reject-all","stableKeys":["ecommerce.progression.review-access-specifications.stored-review-script.9180a"]},{"id":"review-script-unsafe-render","stableKeys":["ecommerce.progression.review-access-specifications.stored-review-script.9180a"]},{"id":"saving-a-staff-role-snaps-the-input-back-to-the-stored-role","stableKeys":["ecommerce.progression.staff-roles.staff-roles.621c"]},{"id":"saving-notification-preferences-resets-the-toggles","stableKeys":["ecommerce.progression.notification-preferences.notification-preferences.630c"]},{"id":"scheduled-restock-execution-queue-is-process-local","stableKeys":["ecommerce.l3.deferred-durability.restart-survival.311a"]},{"id":"session-token-is-not-persisted-for-reload","stableKeys":["ecommerce.spec.state-durability.session-reload.1e"]},{"id":"ship-acknowledges-without-changing-status","stableKeys":["ecommerce.operations-access.fulfilment-queue.1c"]},{"id":"shipping-counts-sale-twice","stableKeys":["ecommerce.inventory-operations.shipping-accounting.202e"]},{"id":"signed-out-purchase-bypasses-account-check","stableKeys":["ecommerce.spec.access-control.signed-out-purchase.3a"]},{"id":"signin-binds-the-second-client-to-a-different-account","stableKeys":["ecommerce.spec.live-state.shared-cart.4c"]},{"id":"signin-does-not-verify-the-password","stableKeys":["ecommerce.feature.accounts.accounts.1c"]},{"id":"signout-keeps-the-account-session","stableKeys":["ecommerce.feature.accounts.accounts.1d"]},{"id":"signup-binds-the-new-account-to-the-admin-session","stableKeys":["ecommerce.feature.accounts.accounts.1a"]},{"id":"staff-admin-access-survives-role-removal","stableKeys":["ecommerce.spec.access-control.staff-role-revocation.621d"]},{"id":"staff-can-assign-roles","stableKeys":["ecommerce.spec.access-control.staff-role-boundary.621b","ecommerce.spec.access-control.staff-role-revocation.621d"]},{"id":"staff-cannot-open-staff-tools","stableKeys":["ecommerce.progression.staff-access.staff-access.601a"]},{"id":"stock-alert-delivery-is-suppressed","stableKeys":["ecommerce.progression.stock-alerts.stock-alert-delivery.631c"]},{"id":"stock-alert-is-sent-after-every-restock","stableKeys":["ecommerce.spec.transactional-integrity.stock-alert-deduplication.631a"]},{"id":"stock-alerts-are-visible-to-other-customers","stableKeys":["ecommerce.spec.access-control.stock-alert-privacy.631b"]},{"id":"stock-subscription-snapshotted-once","stableKeys":["ecommerce.spec.external-data-sync.external-stock.901a"]},{"id":"stock-view-ignores-update-across-app-server-stop","stableKeys":["ecommerce.spec.external-data-sync.external-stock.901c"]},{"id":"stock-view-keeps-pre-reconnect-snapshot","stableKeys":["ecommerce.spec.external-data-sync.external-stock.901d"]},{"id":"stored-support-replies-are-hidden-after-reload","stableKeys":["ecommerce.progression.managed-support.managed-support.613c"]},{"id":"support-assignment-is-discarded","stableKeys":["ecommerce.progression.support-triage.support-assignment.611a"]},{"id":"support-history-is-lost-on-fresh-account-login","stableKeys":["ecommerce.spec.state-durability.support-history-reload.612a"]},{"id":"support-history-leaks-across-customers","stableKeys":["ecommerce.spec.access-control.support-history-logout.612d","ecommerce.spec.access-control.support-history-privacy.612b"]},{"id":"support-history-leaks-to-signed-out-visitors","stableKeys":["ecommerce.spec.access-control.support-history-logout.612d"]},{"id":"support-history-rows-are-hidden","stableKeys":["ecommerce.progression.support-history.support-history.612c","ecommerce.spec.access-control.support-history-logout.612d","ecommerce.spec.access-control.support-history-privacy.612b","ecommerce.spec.state-durability.support-history-reload.612a"]},{"id":"support-priority-is-discarded","stableKeys":["ecommerce.progression.support-triage.support-priority.611b"]},{"id":"support-status-is-discarded","stableKeys":["ecommerce.progression.support-triage.support-status.611c"]},{"id":"transfer-creates-stock-during-race","stableKeys":["ecommerce.inventory-operations.stock-conservation.202d"]},{"id":"transfer-debits-source-without-crediting-existing-destination","stableKeys":["ecommerce.inventory-operations.stock-conservation.202a","ecommerce.inventory-operations.warehouse-transfer.2a","ecommerce.operations-access.operator-authorization.201a"]},{"id":"transfer-skips-the-source-holding-check","stableKeys":["ecommerce.spec.transactional-integrity.stock-transfer-overdraw.2c"]},{"id":"visitor-support-reference-is-hidden","stableKeys":["ecommerce.progression.support-intake.support-intake.610a"]},{"id":"warehouse-totals-are-frozen-at-page-load","stableKeys":["ecommerce.spec.live-state.stock-transfers.2b"]},{"id":"warehouse-view-omits-west","stableKeys":["ecommerce.feature.warehouse-admin.warehouse-view.7b"]}]}],"nullControl":{"pointBearing":"must-fail-conclusively","repetitions":1,"zeroPoint":"typed-policy"},"qualification":{"checks":["ecommerce.feature.accounts.accounts.1a","ecommerce.feature.accounts.accounts.1b","ecommerce.feature.accounts.accounts.1c","ecommerce.feature.accounts.accounts.1d","ecommerce.feature.cart-checkout.cart.4a","ecommerce.feature.cart-checkout.cart.4d","ecommerce.feature.catalog.catalog-ranking.2b","ecommerce.feature.catalog.catalog-search.2d","ecommerce.feature.catalog.catalog-values.2a","ecommerce.feature.purchasing.purchase-order.3c","ecommerce.feature.reviews.reviews.6a","ecommerce.feature.warehouse-admin.admin-write.103a","ecommerce.feature.warehouse-admin.warehouse-view.7b","ecommerce.inventory-operations.operational-views.5c","ecommerce.inventory-operations.operational-views.5d","ecommerce.inventory-operations.operational-views.5e","ecommerce.inventory-operations.operational-views.5f","ecommerce.inventory-operations.shipping-accounting.202e","ecommerce.inventory-operations.stock-conservation.202a","ecommerce.inventory-operations.stock-conservation.202b","ecommerce.inventory-operations.stock-conservation.202c","ecommerce.inventory-operations.stock-conservation.202d","ecommerce.inventory-operations.warehouse-transfer.2a","ecommerce.l3.deferred-access.scheduled-work-access.317a","ecommerce.l3.deferred-durability.restart-survival.311a","ecommerce.l3.deferred-integrity.exactly-once.311a","ecommerce.l3.scheduled-restocks.scheduled-restocks.302a","ecommerce.l3.scheduled-restocks.scheduled-restocks.305a","ecommerce.l3.scheduled-restocks.scheduled-restocks.306a","ecommerce.l3.server-time.server-time.312a","ecommerce.operations-access.fulfilment-queue.1b","ecommerce.operations-access.fulfilment-queue.1c","ecommerce.operations-access.operator-authorization.201a","ecommerce.operations-access.operator-authorization.201c","ecommerce.operations-access.order-owner.204a","ecommerce.progression.catalog-management.catalog-management.622a","ecommerce.progression.catalog-management.catalog-management.622b","ecommerce.progression.customer-profile.customer-profile.620c","ecommerce.progression.faceted-search.faceted-search.401a","ecommerce.progression.faceted-search.faceted-search.402a","ecommerce.progression.managed-support.managed-support.613c","ecommerce.progression.notification-preferences.notification-preferences.630c","ecommerce.progression.promotion-rules.promotion-rule-values.620a","ecommerce.progression.review-access-specifications.review-eligibility-direct.618a","ecommerce.progression.review-access-specifications.stored-review-script.9180a","ecommerce.progression.staff-access.staff-access.601a","ecommerce.progression.staff-roles.staff-roles.621c","ecommerce.progression.stock-alerts.stock-alert-delivery.631c","ecommerce.progression.support-history.support-history.612c","ecommerce.progression.support-intake.support-intake.610a","ecommerce.progression.support-triage.support-assignment.611a","ecommerce.progression.support-triage.support-priority.611b","ecommerce.progression.support-triage.support-status.611c","ecommerce.returns-pricing.cancellation-and-return.3a","ecommerce.returns-pricing.cancellation-and-return.3b","ecommerce.returns-pricing.refund-accounting.203a","ecommerce.spec.access-control.cart-boundary.109a","ecommerce.spec.access-control.cart-boundary.109b","ecommerce.spec.access-control.customer-profile-privacy.620b","ecommerce.spec.access-control.fulfilment-area-boundary.1d","ecommerce.spec.access-control.managed-support-privacy.613b","ecommerce.spec.access-control.notification-preferences-privacy.630b","ecommerce.spec.access-control.order-ownership.106a","ecommerce.spec.access-control.promotion-management-boundary.620b","ecommerce.spec.access-control.purchase-attribution.102a","ecommerce.spec.access-control.purchase-session.101a","ecommerce.spec.access-control.review-eligibility.108a","ecommerce.spec.access-control.review-eligibility.108b","ecommerce.spec.access-control.signed-out-purchase.3a","ecommerce.spec.access-control.staff-area-boundary.601b","ecommerce.spec.access-control.staff-role-boundary.621b","ecommerce.spec.access-control.staff-role-revocation.621d","ecommerce.spec.access-control.stock-alert-privacy.631b","ecommerce.spec.access-control.support-history-logout.612d","ecommerce.spec.access-control.support-history-privacy.612b","ecommerce.spec.access-control.warehouse-area-boundary.7a","ecommerce.spec.access-control.warehouse-write-boundary.103b","ecommerce.spec.concurrency-safety.duplicate-checkout.203a","ecommerce.spec.concurrency-safety.duplicate-checkout.203b","ecommerce.spec.concurrency-safety.last-unit.201a","ecommerce.spec.concurrency-safety.last-unit.201b","ecommerce.spec.concurrency-safety.last-unit.201c","ecommerce.spec.concurrency-safety.restock-race.202a","ecommerce.spec.external-data-sync.external-stock.901a","ecommerce.spec.external-data-sync.external-stock.901c","ecommerce.spec.external-data-sync.external-stock.901d","ecommerce.spec.live-state.fulfilment-queue.1a","ecommerce.spec.live-state.inventory-dashboard.5a","ecommerce.spec.live-state.managed-support.613a","ecommerce.spec.live-state.open-list.902a","ecommerce.spec.live-state.purchase-stock.3b","ecommerce.spec.live-state.ranking.2c","ecommerce.spec.live-state.rating.6c","ecommerce.spec.live-state.sales-dashboard.5b","ecommerce.spec.live-state.shared-cart.4c","ecommerce.spec.live-state.stock-transfers.2b","ecommerce.spec.live-state.warehouse-stock.7c","ecommerce.spec.search-ordering.search-ordering.402b","ecommerce.spec.state-durability.account-state-recovery.105a","ecommerce.spec.state-durability.account-state-recovery.105b","ecommerce.spec.state-durability.cart-reload.4b","ecommerce.spec.state-durability.checkout-crash-durability.910b","ecommerce.spec.state-durability.checkout-crash-integrity.910a","ecommerce.spec.state-durability.customer-profile-reload.620a","ecommerce.spec.state-durability.notification-preferences-reload.630a","ecommerce.spec.state-durability.session-reload.1e","ecommerce.spec.state-durability.staff-role-reload.621a","ecommerce.spec.state-durability.support-history-reload.612a","ecommerce.spec.transactional-integrity.books-balance.107a","ecommerce.spec.transactional-integrity.books-balance.107b","ecommerce.spec.transactional-integrity.server-price.104a","ecommerce.spec.transactional-integrity.stock-alert-deduplication.631a","ecommerce.spec.transactional-integrity.stock-transfer-overdraw.2c","ecommerce.spec.transactional-integrity.unique-review.6b"],"evidence":[],"exactCombinationRequired":true,"featureCatalog":{"contentSha256":"8671f7883c2e5a24474a546ef1517407cd9334258e1a7cfe91e292a9af1952f2","id":"ecommerce.questlines","path":"progression/ecommerce.json"},"mutationRepetitions":1,"referenceRepetitions":1,"runner":{"architecture":"x64","mode":"appliance","platform":"linux","schemaVersion":1},"stacks":["mongodb","postgres","spacetime"]},"recipe":{"contentSha256":"53fbb8093b2335837d88c246f04da99858c40b57ce24d17fbd2b6c815abdb62d","executionSha256":"558ea7e4033dd1e08c76c2ecc475751f2cabd210f4e18cc0f2c6e3e3531a2498","id":"ecommerce.progression-catalog","meaningSha256":"79dc9a2f8ee5854d3f4edf68862942778d0fa0bd667b35554f065d025726aa76","path":"composition/recipes/progression-catalog.json"},"references":{"entries":[{"backend":"mongodb","id":"ecommerce-reference-mongodb","sourceSha256":"0d21bbc4b2768f4077a81d676f0d4c87a65067dda8f2c5ffeb2fa9208381dc7e","targetPath":"reference-apps/ecommerce/mongodb"},{"backend":"postgres","id":"ecommerce-reference-postgres","sourceSha256":"f3906fa01050f00a0ed76c69c256a6b0013bbf72eb72c03aa92d79e47b71c2b8","targetPath":"reference-apps/ecommerce/postgres"},{"backend":"spacetime","id":"ecommerce-reference-spacetime","sourceSha256":"7ba1f548e89f461b95b5caf843b0fbcf2b81278428d02869d7f47e1a199eaf6e","targetPath":"reference-apps/ecommerce/spacetime"}],"registryPath":"reference-apps/registry.json"},"selection":{"alias":"L3","coveredAliases":["L1","L2","L3"],"path":"composition/dependency.json","sha256":"e73002df8a7a42e612f2bd1ee5de1f9db2d6c13cb9c819e405a5f2512eca3048"},"title":"Ecommerce dependency L3 calibration","track":"ecommerce","qualificationSha256":"253174720de8d80e884e764e4d8018c0a98e1c54b364b33f7679aa189af8d1bd","contentSha256":"11134cdd2ecc17a3843b4808d64b91272abe98682d68922e505508c078af3170","qualificationStaleness":[]},"mutations":{"mongodb":{"schemaVersion":3,"fixtureSha256":"0d21bbc4b2768f4077a81d676f0d4c87a65067dda8f2c5ffeb2fa9208381dc7e","backend":"mongodb","track":"ecommerce","note":"Mutation definitions for the MongoDB ecommerce reference.","mutations":[{"id":"recommendation-dismissal-lost-on-restart","scenario":"tracks/ecommerce/scenarios/progression-recommendation-feedback.json","targets":["ecommerce.spec.state-durability.recommendation-feedback-restart.504c"],"desc":"Erase saved recommendation dismissals when the application starts again.","file":"server/src/index.ts","edits":[{"find":" await mongoose.connect(DATABASE_URL);","replace":" await mongoose.connect(DATABASE_URL);\n await Dismissal.deleteMany({});"}]},{"id":"pending-order-item-return-accepted","scenario":"tracks/ecommerce/scenarios/progression-order-return-boundary.json","targets":["ecommerce.returns-pricing.cancellation-and-return.3f"],"desc":"Accept a pending order return and restore its stock before shipment.","file":"server/src/index.ts","edits":[{"find":"if (!['shipped', 'delivered'].includes(value.status)) throw new Error('No shipped order found');","replace":"if (!['pending', 'shipped', 'delivered'].includes(value.status)) throw new Error('No shipped order found');"}]},{"id":"staff-admin-access-survives-role-removal","scenario":"tracks/ecommerce/scenarios/progression-staff-roles.json","targets":["ecommerce.spec.access-control.staff-role-revocation.621d"],"desc":"Keep administrator access after changing the assigned role back to staff.","file":"server/src/progression.ts","edits":[{"find":" target.isAdmin = role === \"admin\";","replace":" target.isAdmin = target.isAdmin || role === \"admin\";"}]},{"id":"shipping-counts-sale-twice","scenario":"tracks/ecommerce/scenarios/progression-shipping-accounting.json","targets":["ecommerce.inventory-operations.shipping-accounting.202e"],"desc":"Shipping succeeds but doubles the completed sale value in authoritative revenue.","file":"server/src/index.ts","edits":[{"find":" order.status = \"shipped\";\n await order.save();","replace":" order.status = \"shipped\";\n order.total *= 2;\n await order.save();"}]},{"id":"signup-does-not-expose-created-account","scenario":"tracks/ecommerce/scenarios/01-account-create.json","targets":["ecommerce.feature.accounts.accounts.1a"],"desc":"Signup succeeds but the client discards the created account identity from its current session view.","file":"client/src/App.tsx","edits":[{"find":" saveSession(data.token, data.user);\n };\n\n const handleSignIn","replace":" saveSession(data.token, { ...data.user, username: \"\" });\n };\n\n const handleSignIn"}]},{"id":"duplicate-signup-reports-success","scenario":"tracks/ecommerce/scenarios/01-account-duplicate.json","targets":["ecommerce.feature.accounts.accounts.1b"],"desc":"A duplicate username is reported as a successful empty signup response instead of a refusal.","file":"server/src/index.ts","edits":[{"find":" if (existing) return res.status(409).json({ error: \"Username is already taken\" });","replace":" if (existing) return res.json({}); // mutant: duplicate signup is falsely accepted"}]},{"id":"signin-skips-password-verification","scenario":"tracks/ecommerce/scenarios/01-account-password.json","targets":["ecommerce.feature.accounts.accounts.1c"],"desc":"Signin accepts an existing account without requiring its password to match.","file":"server/src/index.ts","edits":[{"find":" if (!valid) return res.status(401).json({ error: \"Invalid username or password\" });","replace":" if (false && !valid) return res.status(401).json({ error: \"Invalid username or password\" });"}]},{"id":"signout-keeps-current-account","scenario":"tracks/ecommerce/scenarios/01-account-signout.json","targets":["ecommerce.feature.accounts.accounts.1d"],"desc":"Signout disconnects the token state but leaves the current account and persisted credential in place.","file":"client/src/App.tsx","edits":[{"find":" const handleSignOut = () => {\n clearSession();\n };","replace":" const handleSignOut = () => {\n setToken(null); // mutant: visible and persisted account state is not cleared\n };"}]},{"id":"session-token-not-persisted","scenario":"tracks/ecommerce/scenarios/01-account-reload.json","targets":["ecommerce.spec.state-durability.session-reload.1e"],"desc":"The active session is kept only in React state and is unavailable after a page reload.","file":"client/src/App.tsx","edits":[{"find":" localStorage.setItem(TOKEN_KEY, tok);\n setToken(tok);","replace":" void tok; // mutant: the session token is never persisted\n setToken(tok);"}]},{"id":"purchase-counts-never-affect-ranking","scenario":"tracks/ecommerce/scenarios/01-core.json","targets":["ecommerce.spec.live-state.ranking.2c"],"desc":"The catalogue ranking ignores recorded purchases and therefore never promotes the bought item.","file":"server/src/index.ts","edits":[{"find":" purchaseCount: purchaseMap.get(id) || 0,","replace":" purchaseCount: 0, // mutant: ranking ignores durable purchase counts"}]},{"id":"signed-out-visitor-purchase-is-accepted","scenario":"tracks/ecommerce/scenarios/progression-signed-out-purchase.json","targets":["ecommerce.spec.access-control.signed-out-purchase.3a"],"desc":"The UI exposes purchase controls to visitors and the buy route assigns unauthenticated requests an unverified identity, allowing an actual stock-debiting order.","file":"client/src/App.tsx","edits":[{"find":" const isCustomer = !!currentUser && !currentUser.isAdmin && !currentUser.isStaff;","replace":" const isCustomer = !currentUser?.isAdmin && !currentUser?.isStaff;"},{"file":"server/src/index.ts","find":"app.post(\"/api/items/:id/buy\", requireAuth, async (req, res) => {","replace":"app.post(\"/api/items/:id/buy\", async (req, _res, next) => {\n (req as any).user = await userFromToken(extractToken(req)) || { _id: new Types.ObjectId() };\n next();\n}, async (req, res) => {"}]},{"id":"espresso-stock-row-ignores-live-updates","scenario":"tracks/ecommerce/scenarios/01-buying.json","targets":["ecommerce.spec.live-state.purchase-stock.3b"],"desc":"The live catalogue handler preserves a stale Espresso Machine stock projection while applying all other item updates.","file":"client/src/App.tsx","edits":[{"find":" socket.on(\"items:update\", (data: ItemT[]) => setItems(data));","replace":" socket.on(\"items:update\", (data: ItemT[]) => setItems((previous) => data.map((item) => item.name === \"Espresso Machine\" ? { ...item, stock: previous.find((old) => old.id === item.id)?.stock ?? item.stock } : item)));"}]},{"id":"restock-race-records-wrong-order-total","scenario":"tracks/ecommerce/scenarios/01-restock-race.json","targets":["ecommerce.spec.concurrency-safety.restock-race.202a"],"desc":"Purchases preserve stock and visible order counts but record the wrong booked total. Native mixed-race reconciliation must reject them.","file":"server/src/index.ts","edits":[{"find":" total: item.price,\n });","replace":" total: 0, // mutant: purchase receipt loses the authoritative price\n });"}]},{"id":"purchase-order-uses-zero-price","scenario":"tracks/ecommerce/scenarios/progression-purchasing.json","targets":["ecommerce.feature.purchasing.purchase-order.3c"],"desc":"A direct purchase records the item but stores a zero order total instead of the price paid.","file":"server/src/index.ts","edits":[{"find":" total: item.price,\n });","replace":" total: 0, // mutant: purchase receipt loses the authoritative price\n });"}]},{"id":"reload-hydrates-an-empty-cart","scenario":"tracks/ecommerce/scenarios/01-cart.json","targets":["ecommerce.spec.state-durability.cart-reload.4b"],"desc":"Cart hydration discards the persisted server response after reload.","file":"client/src/App.tsx","edits":[{"find":" const refreshCart = useCallback(async (tok: string) => {\n const data = await apiFetch(\"/api/cart\", tok);\n setCart(data);\n }, []);","replace":" const refreshCart = useCallback(async (tok: string) => {\n await apiFetch(\"/api/cart\", tok);\n setCart({ items: [], total: 0 }); // mutant: persisted cart response is discarded\n }, []);"}]},{"id":"shared-cart-live-events-ignored","scenario":"tracks/ecommerce/scenarios/01-cart.json","targets":["ecommerce.spec.live-state.shared-cart.4c"],"desc":"An already-open second session ignores committed cart update events.","file":"client/src/App.tsx","edits":[{"find":" socket.on(\"cart:update\", (data: CartT) => setCart(data));","replace":" socket.on(\"cart:update\", (data: CartT) => setCart(current => current.items.length === 0 ? current : data)); // mutant: an empty second-session cart ignores its first remote update"}]},{"id":"review-comment-is-not-persisted","scenario":"tracks/ecommerce/scenarios/01-review-visibility.json","targets":["ecommerce.feature.reviews.reviews.6a"],"desc":"Review submission persists an empty comment rather than the customer's submitted text.","file":"server/src/index.ts","edits":[{"find":" { itemId, userId: user._id, username: user.username, rating: ratingNum,\n comment: typeof comment === \"string\" ? comment : \"\" },","replace":" { itemId, userId: user._id, username: user.username, rating: ratingNum,\n comment: \"\" },"}]},{"id":"repeat-review-uses-a-new-owner-key","scenario":"tracks/ecommerce/scenarios/01-review-uniqueness.json","targets":["ecommerce.spec.transactional-integrity.unique-review.6b"],"desc":"Each review submission is stored under a fresh owner key, bypassing the one-review-per-customer constraint.","file":"server/src/index.ts","edits":[{"find":" { itemId, userId: user._id },\n { itemId, userId: user._id, username: user.username, rating: ratingNum,\n comment: typeof comment === \"string\" ? comment : \"\" },","replace":" { itemId, userId: new Types.ObjectId() },\n { itemId, userId: new Types.ObjectId(), username: user.username, rating: ratingNum,\n comment: typeof comment === \"string\" ? comment : \"\" },"}]},{"id":"live-review-average-uses-an-extra-divisor","scenario":"tracks/ecommerce/scenarios/01-review-rating-live.json","targets":["ecommerce.spec.live-state.rating.6c"],"desc":"The live review event divides the rating sum by one more review than actually exists.","file":"server/src/index.ts","edits":[{"find":"async function broadcastReviews(itemId: string) {\n const reviews = await Review.find({ itemId }).sort({ createdAt: -1 });\n const average = reviews.length ? reviews.reduce((s, r) => s + r.rating, 0) / reviews.length : 0;","replace":"async function broadcastReviews(itemId: string) {\n const reviews = await Review.find({ itemId }).sort({ createdAt: -1 });\n const average = reviews.length ? reviews.reduce((s, r) => s + r.rating, 0) / (reviews.length + 1) : 0;"}]},{"id":"warehouse-view-omits-one-location","scenario":"tracks/ecommerce/scenarios/01-warehouse-admin-staff.json","targets":["ecommerce.feature.warehouse-admin.warehouse-view.7b"],"desc":"The admin warehouse projection truncates the final item-location row.","file":"client/src/App.tsx","edits":[{"find":" {overview.locations.map((loc) => (","replace":" {overview.locations.slice(0, -1).map((loc) => ("}]},{"id":"unauthenticated-purchase-defaults-to-admin","scenario":"tracks/ecommerce/scenarios/01-purchase-session.json","targets":["ecommerce.spec.access-control.purchase-session.101a"],"desc":"The purchase endpoint drops authentication and assigns sessionless purchases to the seeded administrator.","file":"server/src/index.ts","edits":[{"find":"app.post(\"/api/items/:id/buy\", requireAuth, async (req, res) => {","replace":"app.post(\"/api/items/:id/buy\", async (req, res) => {"},{"find":" const user = (req as any).user;\n const order = await Order.create({","replace":" const user = (req as any).user || await User.findOne({ username: \"admin\" });\n const order = await Order.create({"}]},{"id":"direct-purchase-total-ignores-store-price","scenario":"tracks/ecommerce/scenarios/01-server-price.json","targets":["ecommerce.spec.transactional-integrity.server-price.104a"],"desc":"The direct purchase creates one order but records a zero total rather than the store's current price.","file":"server/src/index.ts","edits":[{"find":" total: item.price,\n });","replace":" total: 0, // mutant: direct purchase ignores the authoritative price\n });"}]},{"id":"cart-hydration-loses-account-state","scenario":"tracks/ecommerce/scenarios/progression-account-state-reload.json","targets":["ecommerce.spec.state-durability.account-state-recovery.105a"],"desc":"Reload hydration discards the account's persisted cart response.","file":"client/src/App.tsx","edits":[{"find":" const refreshCart = useCallback(async (tok: string) => {\n const data = await apiFetch(\"/api/cart\", tok);\n setCart(data);\n }, []);","replace":" const refreshCart = useCallback(async (tok: string) => {\n await apiFetch(\"/api/cart\", tok);\n setCart({ items: [], total: 0 }); // mutant: account state is discarded on hydration\n }, []);"}]},{"id":"reconnect-hydration-loses-account-state","scenario":"tracks/ecommerce/scenarios/progression-account-state-reconnect.json","targets":["ecommerce.spec.state-durability.account-state-recovery.105b"],"desc":"The initial account cart loads correctly, but after network restoration the client ignores both refreshed and pushed cart state.","file":"client/src/App.tsx","edits":[{"find":" useEffect(() => {\n const socket = io({ auth: token ? { token } : {} });","replace":" useEffect(() => {\n const clearAccountOffline = () => {\n setCurrentUser(null);\n setCart({ items: [], total: 0 });\n };\n window.addEventListener(\"offline\", clearAccountOffline, { once: true });\n const socket = io({ auth: token ? { token } : {} });"}]},{"id":"order-history-is-not-owner-scoped","scenario":"tracks/ecommerce/scenarios/01-order-ownership.json","targets":["ecommerce.spec.access-control.order-ownership.106a"],"desc":"Order history returns every customer's orders instead of filtering by the authenticated owner.","file":"server/src/index.ts","edits":[{"find":" const orders = await Order.find({ userId }).sort({ createdAt: -1 });","replace":" const orders = await Order.find({}).sort({ createdAt: -1 });"}]},{"id":"revenue-aggregation-ignores-order-totals","scenario":"tracks/ecommerce/scenarios/progression-books-balance.json","targets":["ecommerce.spec.transactional-integrity.books-balance.107a"],"desc":"The admin revenue aggregation counts every order as zero regardless of its stored total.","file":"server/src/index.ts","edits":[{"find":" { $group: { _id: null, total: { $sum: { $subtract: [\"$total\", { $ifNull: [\"$refundTotal\", 0] }] } } } },","replace":" { $group: { _id: null, total: { $sum: 0 } } },"}]},{"id":"unpurchased-review-is-accepted","scenario":"tracks/ecommerce/scenarios/01-review-eligibility.json","targets":["ecommerce.spec.access-control.review-eligibility.108a"],"desc":"The review endpoint bypasses its completed-purchase eligibility check.","file":"server/src/index.ts","edits":[{"find":" if (!hasPurchased) {\n return res.status(403).json({ error: \"You can only review items you have purchased\" });\n }","replace":" if (false && !hasPurchased) {\n return res.status(403).json({ error: \"You can only review items you have purchased\" });\n }"}]},{"id":"purchased-review-ui-does-not-submit","scenario":"tracks/ecommerce/scenarios/01-review-eligibility.json","targets":["ecommerce.spec.access-control.review-eligibility.108b"],"desc":"The review form discards valid customer submissions. Direct authorized and unauthorized review calls retain their normal behavior.","file":"client/src/App.tsx","edits":[{"find":" const handleReviewSubmit = async (itemId: string, rating: number, comment: string) => {\n setReviewError(\"\");","replace":" const handleReviewSubmit = async (itemId: string, rating: number, comment: string) => {\n setReviewError(\"Review submission unavailable\");\n return;"}]},{"id":"external-stock-polling-disabled","scenario":"tracks/ecommerce/scenarios/01-external-live-sync.json","targets":["ecommerce.spec.external-data-sync.external-stock.901a"],"desc":"The server stops reconciling direct database stock writes into live catalogue events.","file":"server/src/index.ts","edits":[{"find":" broadcastItems().catch((err) => console.error(\"broadcastItems poll failed\", err));","replace":" // mutant: direct database stock changes are never reconciled"}]},{"id":"server-restart-disables-catalog-recovery","scenario":"tracks/ecommerce/scenarios/01-external-server-restart-sync.json","targets":["ecommerce.spec.external-data-sync.external-stock.901c"],"desc":"After a socket disconnect, the existing page ignores both reconnect refreshes and later catalogue snapshots.","file":"client/src/App.tsx","edits":[{"find":" const socketRef = useRef(null);\n\n const saveSession","replace":" const socketRef = useRef(null);\n const acceptCatalogRecovery = useRef(true);\n\n const saveSession"},{"find":" socket.on(\"connect\", () => {\n refreshItems().catch((err) => console.error(err));","replace":" socket.on(\"disconnect\", () => { acceptCatalogRecovery.current = false; });\n socket.on(\"connect\", () => {\n if (acceptCatalogRecovery.current) refreshItems().catch((err) => console.error(err));"},{"find":" socket.on(\"items:update\", (data: ItemT[]) => setItems(data));","replace":" socket.on(\"items:update\", (data: ItemT[]) => { if (acceptCatalogRecovery.current) setItems(data); });"}]},{"id":"reconnect-generation-ignores-current-catalog","scenario":"tracks/ecommerce/scenarios/01-external-reconnect-sync.json","targets":["ecommerce.spec.external-data-sync.external-stock.901d"],"desc":"After the browser goes offline, the existing page ignores reconnect refreshes and subsequent catalogue events.","file":"client/src/App.tsx","edits":[{"find":" const socketRef = useRef(null);\n\n const saveSession","replace":" const socketRef = useRef(null);\n const acceptCatalogUpdates = useRef(true);\n useEffect(() => {\n const stopCatalogRecovery = () => { acceptCatalogUpdates.current = false; };\n window.addEventListener(\"offline\", stopCatalogRecovery);\n return () => window.removeEventListener(\"offline\", stopCatalogRecovery);\n }, []);\n\n const saveSession"},{"find":" setItems(data.items);","replace":" if (acceptCatalogUpdates.current) setItems(data.items);"},{"find":" socket.on(\"items:update\", (data: ItemT[]) => setItems(data));","replace":" socket.on(\"items:update\", (data: ItemT[]) => {\n if (acceptCatalogUpdates.current) setItems(data);\n });"}]},{"id":"open-review-list-ignores-live-update","scenario":"tracks/ecommerce/scenarios/progression-open-list-live.json","targets":["ecommerce.spec.live-state.open-list.902a"],"desc":"The already-open review list ignores a committed review update from another client.","file":"client/src/App.tsx","edits":[{"find":" setItemDetail((prev) => (prev && prev.id === payload.itemId ? { ...prev, reviews: payload.reviews, average: payload.average } : prev));","replace":" void payload; // mutant: the already-open review list ignores committed updates"}]},{"id":"cancel-does-not-restore-stock-feature","scenario":"tracks/ecommerce/scenarios/02-order-cancellation-core.json","targets":["ecommerce.returns-pricing.cancellation-and-return.3a"],"desc":"Cancellation changes order state but skips restoration of its recorded warehouse allocations.","file":"server/src/index.ts","edits":[{"find":" {item_id:line.itemId,warehouse_id:allocation.warehouseId}, {$inc:{quantity:allocation.quantity}}, {session});","replace":" {item_id:line.itemId,warehouse_id:allocation.warehouseId}, {$inc:{quantity:0}}, {session});"}]},{"id":"cancellation-accounting-loses-stock-restoration","scenario":"tracks/ecommerce/scenarios/02-invariants.json","targets":["ecommerce.returns-pricing.refund-accounting.203a"],"desc":"Cancellation removes revenue and changes order status, but loses the original warehouse stock restoration. The native refund-accounting assertion must detect this.","file":"server/src/index.ts","edits":[{"find":" {item_id:line.itemId,warehouse_id:allocation.warehouseId}, {$inc:{quantity:allocation.quantity}}, {session});","replace":" {item_id:line.itemId,warehouse_id:allocation.warehouseId}, {$inc:{quantity:0}}, {session});"}]},{"id":"cancel-does-not-restore-stock-fresh-client","scenario":"tracks/ecommerce/scenarios/02-self-contained.json","targets":["ecommerce.inventory-operations.stock-conservation.202b","ecommerce.inventory-operations.stock-conservation.202c"],"desc":"Cancellation changes order state but skips restoration, so a fresh client reads the persisted shortfall.","file":"server/src/index.ts","edits":[{"find":" {item_id:line.itemId,warehouse_id:allocation.warehouseId}, {$inc:{quantity:allocation.quantity}}, {session});","replace":" {item_id:line.itemId,warehouse_id:allocation.warehouseId}, {$inc:{quantity:0}}, {session});"}]},{"id":"cancel-restores-stock-but-keeps-pending-status","scenario":"tracks/ecommerce/scenarios/02-order-cancellation-history.json","targets":["ecommerce.returns-pricing.cancellation-and-return.3b"],"desc":"Cancellation restores allocations but writes pending back to order history.","file":"server/src/index.ts","edits":[{"find":" value.status = \"cancelled\";\n await value.save({session});","replace":" value.status = \"pending\";\n await value.save({session});"}]},{"id":"cancelled-order-remains-in-revenue-feature","scenario":"tracks/ecommerce/scenarios/02-order-cancellation-core.json","targets":["ecommerce.returns-pricing.cancellation-and-return.3a"],"desc":"Admin revenue includes cancelled orders even though cancellation otherwise succeeds.","file":"server/src/index.ts","edits":[{"find":"async function getRevenue(): Promise {\n const rows = await Order.aggregate([\n { $match: { status: { $ne: \"cancelled\" } } },","replace":"async function getRevenue(): Promise {\n const rows = await Order.aggregate([\n { $match: {} },"}]},{"id":"cancelled-order-remains-in-revenue-invariant","scenario":"tracks/ecommerce/scenarios/02-invariants.json","targets":["ecommerce.returns-pricing.refund-accounting.203a"],"desc":"Admin revenue includes cancelled orders even though cancellation otherwise succeeds.","file":"server/src/index.ts","edits":[{"find":"async function getRevenue(): Promise {\n const rows = await Order.aggregate([\n { $match: { status: { $ne: \"cancelled\" } } },","replace":"async function getRevenue(): Promise {\n const rows = await Order.aggregate([\n { $match: {} },"}]},{"id":"operator-authorization-allows-customer-transfer","scenario":"tracks/ecommerce/scenarios/02-strengthened.json","targets":["ecommerce.operations-access.operator-authorization.201a"],"desc":"The transfer route keeps authentication but drops its administrator role gate.","file":"server/src/index.ts","edits":[{"find":"app.post(\"/api/admin/transfer\", requireAuth, requireAdmin, async (req, res) => {","replace":"app.post(\"/api/admin/transfer\", requireAuth, async (req, res) => {"}]},{"id":"customer-can-ship-order-direct-1-1","scenario":"tracks/ecommerce/scenarios/02-server-actions.json","targets":["ecommerce.operations-access.operator-authorization.201c"],"desc":"The shipping route keeps authentication but drops its staff role gate.","file":"server/src/index.ts","edits":[{"find":"app.post(\"/api/fulfilment/ship\", requireAuth, requireStaff, async (req, res) => {","replace":"app.post(\"/api/fulfilment/ship\", requireAuth, async (req, res) => {"}]},{"id":"customer-can-cancel-foreign-order-1-1","scenario":"tracks/ecommerce/scenarios/02-server-actions.json","targets":["ecommerce.operations-access.order-owner.204a"],"desc":"Cancellation retains authentication and pending-state validation but drops order ownership.","file":"server/src/index.ts","edits":[{"find":" const value = orderId ? await Order.findOne({ _id: orderId, userId: user._id }).session(session) : null;\n if (!value) return null;\n if (value.status !== \"pending\") throw new Error(\"Order cannot be cancelled\");","replace":" const value = orderId ? await Order.findOne({ _id: orderId }).session(session) : null;\n if (!value) return null;\n if (value.status !== \"pending\") throw new Error(\"Order cannot be cancelled\");"}]},{"id":"queue-depth-lags-one-order","scenario":"tracks/ecommerce/scenarios/02-fulfilment-live.json","targets":["ecommerce.operations-access.fulfilment-queue.1a"],"desc":"The queue renders every order but its visible depth remains one behind.","file":"client/src/App.tsx","edits":[{"find":"Orders waiting: {queue.depth}","replace":"Orders waiting: {Math.max(0, queue.depth - 1)}"}]},{"id":"ship-acknowledges-without-changing-status","scenario":"tracks/ecommerce/scenarios/02-fulfilment-ship.json","targets":["ecommerce.operations-access.fulfilment-queue.1c"],"desc":"Shipping returns success but writes pending back to the order, leaving both live views unchanged.","file":"server/src/index.ts","edits":[{"find":" order.status = \"shipped\";\n await order.save();","replace":" order.status = \"pending\";\n await order.save();"}]},{"id":"customer-sees-fulfilment-navigation","scenario":"tracks/ecommerce/scenarios/02-features.json","targets":["ecommerce.operations-access.fulfilment-queue.1d"],"desc":"Expose the protected staff area to signed-in customers, including its navigation and content.","file":"client/src/App.tsx","edits":[{"find":" {(currentUser?.isStaff || currentUser?.isAdmin) && (\n ","replace":" setState((value: any) => ({ ...value, preference: { ...preference, order: !preference.order } }))} />"},{"find":"function SupportTicket({ ticket, user, orders, act }: any) {","replace":"function OrderNotificationToggle({ on, onToggle }: { on: boolean; onToggle: () => void }) {\n const [shown] = useState(on); // mutant: the toggle keeps the state loaded when the card opened\n return ;\n}\n\nfunction SupportTicket({ ticket, user, orders, act }: any) {"}]},{"id":"role-editor-snaps-back-to-stored-role","scenario":"tracks/ecommerce/scenarios/progression-staff-roles.json","targets":["ecommerce.progression.staff-roles.staff-roles.621c"],"desc":"Pressing Save persists the role but resets the dropdown to the role that was stored before the save, so the assignment is not visible until a reload.","file":"client/src/ProgressionPanel.tsx","edits":[{"find":" ","replace":" "}]},{"id":"queue-ignores-live-fulfilment-updates","scenario":"tracks/ecommerce/scenarios/02-fulfilment-live.json","targets":["ecommerce.spec.live-state.fulfilment-queue.1a"],"desc":"The open staff queue ignores live fulfilment events, so a new order appears only after a reload.","file":"client/src/App.tsx","edits":[{"find":" socket.on(\"fulfilment:update\", (data: FulfilmentQueueT) => setFulfilmentQueue(data));","replace":" socket.on(\"fulfilment:update\", (data: FulfilmentQueueT) => { void data; }); // mutant: the open staff queue ignores live fulfilment updates"}]},{"id":"low-stock-boundary-excludes-ten-live","scenario":"tracks/ecommerce/scenarios/02-low-stock.json","targets":["ecommerce.spec.live-state.inventory-dashboard.5a"],"desc":"The low-stock view uses a strict boundary, so an item that falls to exactly ten units never joins the list.","file":"server/src/index.ts","edits":[{"find":" .filter((it) => it.stock <= 10)","replace":" .filter((it) => it.stock < 10)"}]},{"id":"live-admin-updates-keep-stale-category-totals","scenario":"tracks/ecommerce/scenarios/02-operational-category-totals.json","targets":["ecommerce.spec.live-state.sales-dashboard.5b"],"desc":"Live admin updates keep the category totals loaded at page load, so a purchase does not move units or revenue until a reload.","file":"client/src/App.tsx","edits":[{"find":" socket.on(\"admin:update\", (data: AdminOverviewT) => setAdminOverview(data));","replace":" socket.on(\"admin:update\", (data: AdminOverviewT) => setAdminOverview((previous) => previous ? { ...data, categories: previous.categories } : data)); // mutant: live admin updates keep the category totals loaded at page load"}]},{"id":"overdraw-transfer-is-accepted","scenario":"tracks/ecommerce/scenarios/02-transfer-overdraw.json","targets":["ecommerce.spec.transactional-integrity.stock-transfer-overdraw.2c"],"desc":"The atomic source debit no longer requires sufficient quantity, so an overdrawn transfer succeeds and moves both warehouse totals.","file":"server/src/index.ts","edits":[{"find":"{ item_id: itemId, warehouse_id: fromWarehouseId, quantity: { $gte: qty } }","replace":"{ item_id: itemId, warehouse_id: fromWarehouseId }"}]},{"id":"transfer-totals-omit-destination-credit-live","scenario":"tracks/ecommerce/scenarios/02-transfer-totals.json","targets":["ecommerce.spec.live-state.stock-transfers.2b"],"desc":"A transfer debits the source but adds zero to the destination, so the two live warehouse totals do not move in opposite directions.","file":"server/src/index.ts","edits":[{"find":" await Stock.findOneAndUpdate(\n { item_id: itemId, warehouse_id: toWarehouseId },\n { $inc: { quantity: qty } },\n { upsert: true }\n );","replace":" await Stock.findOneAndUpdate(\n { item_id: itemId, warehouse_id: toWarehouseId },\n { $inc: { quantity: 0 } },\n { upsert: true }\n );"}]},{"id":"credit-checkout-ignores-wallet","desc":"A credit checkout pays entirely externally despite available credit.","scenario":"tracks/ecommerce/scenarios/progression-store-credit.json","targets":["ecommerce.feature.store-credit.store-credit-750.750a"],"file":"server/src/credit.ts","edits":[{"find":" const creditMinor = useCredit ? Math.min(user.creditMinor, totalMinor) : 0;","replace":" const creditMinor = 0;"}]},{"id":"credit-grant-replay-increments-balance","desc":"Replaying a grant applies its credit to the wallet again.","scenario":"tracks/ecommerce/scenarios/progression-store-credit.json","targets":["ecommerce.spec.store-credit.production-752.752a"],"file":"server/src/credit.ts","edits":[{"find":" if (existing.amountMinor !== amountMinor) throw new Error('Reference already identifies another grant');\n return;","replace":" if (existing.amountMinor !== amountMinor) throw new Error('Reference already identifies another grant');\n await User.updateOne({ _id: accountId }, { $inc: { creditMinor: amountMinor } }, { session });\n return;"}]},{"id":"customer-can-grant-credit","desc":"Customer authentication is accepted without staff authorization.","scenario":"tracks/ecommerce/scenarios/progression-store-credit.json","targets":["ecommerce.spec.store-credit.production-753.753a"],"file":"server/src/credit.ts","edits":[{"find":" app.post('/api/staff/credit', auth, staff, async (req, res) => {","replace":" app.post('/api/staff/credit', auth, async (req, res) => {"}]},{"id":"credit-checkout-retains-purchased-cart","desc":"A second checkout can reuse the purchased cart and create another order.","scenario":"tracks/ecommerce/scenarios/progression-store-credit.json","targets":["ecommerce.spec.store-credit.production-754.754a"],"file":"server/src/credit.ts","edits":[{"find":" cart.items = cart.items.filter(line => line.reservationExpiresAt && line.reservationExpiresAt <= now) as any;","replace":" // mutant: purchased cart lines remain"}]},{"id":"split-refund-does-not-restore-credit","desc":"The refund is recorded but its original wallet credit is not restored.","scenario":"tracks/ecommerce/scenarios/progression-split-tender-refunds.json","targets":["ecommerce.feature.split-tender-refunds.split-tender-refunds-751.751a"],"file":"server/src/progression.ts","edits":[{"find":" await refundCredit(order, session);","replace":" // mutant: omit wallet restoration"}]},{"id":"split-refund-duplicates-credit","desc":"A refund credits the wallet twice while recording one refund.","scenario":"tracks/ecommerce/scenarios/progression-split-tender-refunds.json","targets":["ecommerce.spec.split-tender-refunds.production-756.756a"],"file":"server/src/credit.ts","edits":[{"find":"{ $inc: { creditMinor: delta } }, { session });","replace":"{ $inc: { creditMinor: delta * 2 } }, { session });"}]},{"id":"subscription-skips-due-purchase","desc":"Due deliveries are recorded as skipped although stock is available.","scenario":"tracks/ecommerce/scenarios/progression-subscriptions.json","targets":["ecommerce.feature.subscriptions.subscriptions-760.760a"],"file":"server/src/subscriptions.ts","edits":[{"find":" const allocation = await reserveStock(row.itemId, row.quantity, session);","replace":" const allocation = row.quantity < 0 ? await reserveStock(row.itemId, row.quantity, session) : null;"}]},{"id":"subscription-allows-foreign-cancellation","desc":"A customer can cancel another customer subscription.","scenario":"tracks/ecommerce/scenarios/progression-subscriptions.json","targets":["ecommerce.spec.subscriptions.production-762.762a"],"file":"server/src/subscriptions.ts","edits":[{"find":" if (!row || String(row.userId) !== String((req as any).user._id)) return false;","replace":" if (!row) return false;"}]},{"id":"subscription-pause-is-not-recorded","desc":"Pause acknowledges the request but the subscription remains active.","scenario":"tracks/ecommerce/scenarios/progression-subscriptions.json","targets":["ecommerce.spec.subscriptions.production-763.763a"],"file":"server/src/subscriptions.ts","edits":[{"find":" row.status = 'paused'; row.pausedAt = new Date();","replace":" row.status = 'active'; row.pausedAt = new Date();"}]},{"id":"credit-balance-is-cleared-at-startup","desc":"Restart clears an issued wallet balance while leaving accounts present.","file":"server/src/index.ts","scenario":"tracks/ecommerce/scenarios/progression-store-credit.json","targets":["ecommerce.spec.store-credit.production-755.755a"],"edits":[{"find":" await seed();","replace":" await seed();\n await User.updateMany({}, { $set: { creditMinor: 0 } });"}]},{"id":"pending-subscriptions-are-cleared-at-startup","desc":"Restart erases pending subscription work while preserving ordinary timer execution.","file":"server/src/index.ts","scenario":"tracks/ecommerce/scenarios/progression-subscriptions.json","targets":["ecommerce.spec.subscriptions.production-761.761a"],"edits":[{"find":" await seed();","replace":" await seed();\n await mongoose.connection.collection(\"purchasesubscriptions\").deleteMany({ status: \"active\" });"}]},{"id":"bundle-definition-loses-component-quantity","scenario":"tracks/ecommerce/scenarios/progression-product-bundles.json","targets":["ecommerce.feature.product-bundles.product-bundles.740a"],"desc":"definition loses component quantity","file":"server/src/bundles.ts","edits":[{"find":"quantity: component.quantity });","replace":"quantity: 1 });"}]},{"id":"bundle-catalog-write-allows-customers","scenario":"tracks/ecommerce/scenarios/progression-product-bundles.json","targets":["ecommerce.spec.bundle-integrity.bundle-743.743a"],"desc":"catalog write allows customers","file":"server/src/bundles.ts","edits":[{"find":"if (!actor.isAdmin && !actor.roles?.includes('catalog'))","replace":"if (false)"}]},{"id":"bundle-checkout-price-not-snapshot","scenario":"tracks/ecommerce/scenarios/progression-bundle-checkout.json","targets":["ecommerce.feature.bundle-checkout.bundle-checkout.741a"],"desc":"checkout price not snapshot","file":"server/src/bundles.ts","edits":[{"find":"bundlePrice: bundle.price,","replace":"bundlePrice: bundle.price + 1,"}]},{"id":"bundle-expiry-does-not-release-components","scenario":"tracks/ecommerce/scenarios/progression-bundle-checkout.json","targets":["ecommerce.spec.bundle-integrity.bundle-746.746a"],"desc":"expiry does not release components","file":"server/src/bundles.ts","edits":[{"find":"await releaseBundle(line.componentAllocations as Allocation[], session);\n line.componentAllocations = [] as any;","replace":"line.componentAllocations = [] as any; // mutant: component holds leak"}]},{"id":"bundle-return-loses-original-components","scenario":"tracks/ecommerce/scenarios/progression-bundle-returns.json","targets":["ecommerce.feature.bundle-returns.bundle-returns.742a"],"desc":"return loses original components","file":"server/src/bundles.ts","edits":[{"find":"for (const line of bundles) { await releaseBundle(line.componentAllocations as Allocation[], session); line.returned = true; }","replace":"for (const line of bundles) { line.returned = true; }"}]},{"id":"bundle-return-replay-restocks-again","scenario":"tracks/ecommerce/scenarios/progression-bundle-returns.json","targets":["ecommerce.spec.bundle-integrity.bundle-742.742b"],"desc":"return replay restocks again","file":"server/src/bundles.ts","edits":[{"find":"line.isBundle && !line.returned","replace":"line.isBundle"}]},{"id":"bundle-return-crosses-account-boundary","scenario":"tracks/ecommerce/scenarios/progression-bundle-returns.json","targets":["ecommerce.spec.bundle-integrity.bundle-748.748a"],"desc":"return crosses account boundary","file":"server/src/bundles.ts","edits":[{"find":"{ _id: req.params.orderId, userId, status: { $in: ['shipped', 'delivered'] } }","replace":"{ _id: req.params.orderId, status: { $in: ['shipped', 'delivered'] } }"}]},{"id":"bundle-components-can-overdraw","scenario":"tracks/ecommerce/scenarios/progression-bundle-checkout.json","targets":["ecommerce.spec.bundle-integrity.bundle-744.744a","ecommerce.spec.bundle-integrity.bundle-745.745a"],"desc":"components can overdraw","file":"server/src/stock-reservations.ts","edits":[{"find":"{ item_id: itemId, quantity: { $gte: 1 } }","replace":"{ item_id: itemId }"}]},{"id":"bundle-checkout-reuses-reservation","scenario":"tracks/ecommerce/scenarios/progression-bundle-checkout.json","targets":["ecommerce.spec.bundle-integrity.bundle-747.747a"],"desc":"checkout reuses reservation","file":"server/src/credit.ts","edits":[{"find":"cart.items = cart.items.filter(line => line.reservationExpiresAt && line.reservationExpiresAt <= now) as any;","replace":"// mutant: active cart survives checkout"}]},{"id":"return-after-support-refund-is-blocked","scenario":"tracks/ecommerce/scenarios/progression-support-return-interaction.json","targets":["ecommerce.feature.split-tender-refunds.return-refund-interaction.757a"],"desc":"Reject a valid physical return after a financial refund.","file":"server/src/index.ts","edits":[{"find":" if (!line || line.returned) throw new Error('No returnable item found');","replace":" if (!line || line.returned || value.refundTotal > 0) throw new Error('No returnable item found');"}]},{"id":"support-refund-after-return-pays-twice","scenario":"tracks/ecommerce/scenarios/progression-support-return-interaction.json","targets":["ecommerce.feature.split-tender-refunds.return-refund-interaction.757b"],"desc":"Pay the full order again after a physical return.","file":"server/src/progression.ts","edits":[{"find":" order.refundTotal = order.total;","replace":" order.refundTotal += order.total;"}]},{"id":"support-history-leaks-to-signed-out-visitors","scenario":"tracks/ecommerce/scenarios/progression-support-history.json","targets":["ecommerce.spec.access-control.support-history-logout.612d"],"desc":"Disclose support tickets to signed-out visitors while leaving signed-in ownership filtering unchanged.","file":"server/src/progression.ts","edits":[{"find":"const ticketFilter = isStaff ? {} : user ? { userId: user._id } : { _id: null };","replace":"const ticketFilter = isStaff ? {} : user ? { userId: user._id } : {};"}]},{"id":"checkout-crash-integrity","scenario":"tracks/ecommerce/scenarios/progression-checkout-crash.json","targets":["ecommerce.spec.state-durability.checkout-crash-integrity.910a"],"desc":"A lifecycle callback changes a prepared or cleared cart to quantity two, leaving neither a legal rollback nor a complete checkout.","file":"server/src/index.ts","edits":[{"find":" await initializeOrderData(mongoose.connection);","replace":" await initializeOrderData(mongoose.connection);\n for (const cart of await Cart.find()) { const order = await Order.findOne({ userId: cart.userId }); if (order?.items[0]) await Cart.updateOne({ _id: cart._id }, { $set: { items: [{ itemId: order.items[0].itemId, quantity: 2 }] } }); }"}]},{"id":"checkout-crash-durability","scenario":"tracks/ecommerce/scenarios/progression-checkout-crash.json","targets":["ecommerce.spec.state-durability.checkout-crash-durability.910b"],"desc":"A lifecycle callback corrupts earlier order totals. The unchanged prepared snapshots and acknowledged baseline must expose the damage.","file":"server/src/index.ts","edits":[{"find":" await initializeOrderData(mongoose.connection);","replace":" await initializeOrderData(mongoose.connection);\n await Order.updateMany({}, { $set: { total: 0 } });"}]},{"id":"review-script-unsafe-render","scenario":"tracks/ecommerce/scenarios/progression-review-script.json","targets":["ecommerce.progression.review-access-specifications.stored-review-script.9180a"],"desc":"Render stored review text as HTML so it executes in another customer session.","file":"client/src/App.tsx","edits":[{"find":"
{r.comment}
","replace":"
"}]},{"id":"review-script-reject-all","scenario":"tracks/ecommerce/scenarios/progression-review-script.json","targets":["ecommerce.progression.review-access-specifications.stored-review-script.9180a"],"desc":"Reject all nonempty reviews, including the required benign review; absence of script is insufficient.","file":"server/src/index.ts","edits":[{"find":"const { rating, comment } = req.body || {};","replace":"const { rating, comment } = req.body || {};\n if (String(comment).length > 0) { res.status(400).json({ error: \"Review rejected\" }); return; }"}]},{"id":"review-owner-trust-username","scenario":"tracks/ecommerce/scenarios/progression-review-access.json","targets":["ecommerce.progression.review-access-specifications.review-eligibility-direct.618a"],"desc":"Trust the submitted buyer username instead of the authenticated caller.","file":"server/src/index.ts","edits":[{"find":"const user = (req as any).user;\n const hasPurchased = await Order.exists","replace":"const user = req.body?.username ? await User.findOne({ username: req.body.username }) : (req as any).user;\n const hasPurchased = await Order.exists"}]},{"id":"review-owner-deny-after-write","scenario":"tracks/ecommerce/scenarios/progression-review-access.json","targets":["ecommerce.progression.review-access-specifications.review-eligibility-direct.618a"],"desc":"Replace the buyer review under a forged username, then return a refusal.","file":"server/src/index.ts","edits":[{"find":"const user = (req as any).user;\n const hasPurchased = await Order.exists","replace":"const user = req.body?.username ? await User.findOne({ username: req.body.username }) : (req as any).user;\n const hasPurchased = await Order.exists"},{"find":"await broadcastReviews(String(itemId));","replace":"if (req.body?.username) return res.status(403).json({ error: \"Refused after write\" });\n await broadcastReviews(String(itemId));"}]},{"id":"review-owner-reject-all","scenario":"tracks/ecommerce/scenarios/progression-review-access.json","targets":["ecommerce.progression.review-access-specifications.review-eligibility-direct.618a"],"desc":"Reject the legitimate buyer review as well as unauthorized reviews.","file":"server/src/index.ts","edits":[{"find":"const { rating, comment } = req.body || {};","replace":"const { rating, comment } = req.body || {};\n if (String(comment).length > 0) { res.status(403).json({ error: \"Reject all reviews\" }); return; }"}]}]},"postgres":{"schemaVersion":3,"fixtureSha256":"f3906fa01050f00a0ed76c69c256a6b0013bbf72eb72c03aa92d79e47b71c2b8","backend":"postgres","track":"ecommerce","note":"Mutation definitions for the PostgreSQL ecommerce reference.","mutations":[{"id":"recommendation-dismissal-lost-on-restart","scenario":"tracks/ecommerce/scenarios/progression-recommendation-feedback.json","targets":["ecommerce.spec.state-durability.recommendation-feedback-restart.504c"],"desc":"Erase saved recommendation dismissals when the application starts again.","file":"server/src/index.ts","edits":[{"find":" await initializeProgressionSchema(pool);","replace":" await initializeProgressionSchema(pool);\n await pool.query('DELETE FROM recommendation_dismissal');"}]},{"id":"pending-order-item-return-accepted","scenario":"tracks/ecommerce/scenarios/progression-order-return-boundary.json","targets":["ecommerce.returns-pricing.cancellation-and-return.3f"],"desc":"Accept a pending order return and restore its stock before shipment.","file":"server/src/index.ts","edits":[{"find":"if (!['shipped', 'delivered'].includes(orderRow.rows[0].status)) {","replace":"if (!['pending', 'shipped', 'delivered'].includes(orderRow.rows[0].status)) {"}]},{"id":"staff-admin-access-survives-role-removal","scenario":"tracks/ecommerce/scenarios/progression-staff-roles.json","targets":["ecommerce.spec.access-control.staff-role-revocation.621d"],"desc":"Keep administrator access after changing the assigned role back to staff.","file":"server/src/progression.ts","edits":[{"find":"is_admin = ($1 = 'admin')","replace":"is_admin = (is_admin OR $1 = 'admin')"}]},{"id":"shipping-counts-sale-twice","scenario":"tracks/ecommerce/scenarios/progression-shipping-accounting.json","targets":["ecommerce.inventory-operations.shipping-accounting.202e"],"desc":"Shipping succeeds but doubles the completed sale value in authoritative revenue.","file":"server/src/index.ts","edits":[{"find":"`UPDATE orders SET status = 'shipped', shipped_at = now()\n WHERE id = $1 AND status = 'pending' RETURNING account_id`","replace":"`UPDATE orders SET status = 'shipped', shipped_at = now(), total = total * 2\n WHERE id = $1 AND status = 'pending' RETURNING account_id`"}]},{"id":"signup-ui-does-not-enter-created-account","scenario":"tracks/ecommerce/scenarios/01-account-create.json","targets":["ecommerce.feature.accounts.accounts.1a"],"desc":"Create the account successfully but discard the returned signed-in identity in the client.","file":"client/src/App.tsx","edits":[{"find":" const r = await api<{ account: Account }>(\"/api/auth/signup\", {\n method: \"POST\",\n body: JSON.stringify({ username, password }),\n });\n setAccount(r.account);","replace":" const r = await api<{ account: Account }>(\"/api/auth/signup\", {\n method: \"POST\",\n body: JSON.stringify({ username, password }),\n });\n void r;\n setAccount(null);"}]},{"id":"duplicate-signup-authenticates-existing-account","scenario":"tracks/ecommerce/scenarios/01-account-duplicate.json","targets":["ecommerce.feature.accounts.accounts.1b"],"desc":"Treat a duplicate signup as a successful session for the pre-existing account.","file":"server/src/index.ts","edits":[{"find":" if (existing.length > 0) {\n res.status(409).json({ error: \"username already taken\" });\n return;\n }","replace":" if (existing.length > 0) {\n const token = newToken();\n await db.insert(session).values({ id: token, accountId: existing[0].id });\n res.cookie(\"sid\", token, { httpOnly: true, sameSite: \"lax\", path: \"/\" });\n res.json({ account: { id: existing[0].id, username, isAdmin: false, isStaff: false } });\n return;\n }"}]},{"id":"password-verification-is-inverted","scenario":"tracks/ecommerce/scenarios/01-account-password.json","targets":["ecommerce.feature.accounts.accounts.1c"],"desc":"Accept a wrong password instead of enforcing password verification.","file":"server/src/index.ts","edits":[{"find":" if (rows.length === 0 || !verifyPassword(password, rows[0].passwordHash)) {","replace":" if (rows.length === 0 || verifyPassword(password, rows[0].passwordHash)) {"}]},{"id":"correct-signin-is-refused","scenario":"tracks/ecommerce/scenarios/01-account-signout.json","targets":["ecommerce.feature.accounts.accounts.1d"],"desc":"Preserve wrong-password refusal but reject an otherwise valid sign-in, preventing a signed-out account from returning.","file":"server/src/index.ts","edits":[{"find":" const acc = rows[0];\n const token = newToken();","replace":" const acc = rows[0];\n if (username === acc.username) {\n res.status(401).json({ error: \"sign in is unavailable\" });\n return;\n }\n const token = newToken();"}]},{"id":"reload-discards-session-identity","scenario":"tracks/ecommerce/scenarios/01-account-reload.json","targets":["ecommerce.spec.state-durability.session-reload.1e"],"desc":"Ignore the authenticated identity returned during initial page hydration.","file":"client/src/App.tsx","edits":[{"find":" setAccount(me.account);","replace":" setAccount(null);"}]},{"id":"purchase-does-not-broadcast-ranking","scenario":"tracks/ecommerce/scenarios/01-core.json","targets":["ecommerce.spec.live-state.ranking.2c"],"desc":"Commit the purchase but omit the catalog broadcast that updates already-open rankings.","file":"server/src/index.ts","edits":[{"find":" lastCatalogJson = json;\n io.emit(\"items:update\", { items: catalog });","replace":" lastCatalogJson = json;\n // mutant: changed catalog state is not broadcast"}]},{"id":"signed-out-purchase-uses-default-account","scenario":"tracks/ecommerce/scenarios/progression-signed-out-purchase.json","targets":["ecommerce.spec.access-control.signed-out-purchase.3a"],"desc":"Expose purchase controls to guests and let the purchase route charge the first stored account when no caller is authenticated.","file":"client/src/App.tsx","edits":[{"find":" const canBuy = !!account && !account.isAdmin && !account.isStaff;","replace":" const canBuy = !account || (!account.isAdmin && !account.isStaff);"},{"file":"server/src/index.ts","find":" \"/api/items/:id/buy\",\n requireAuth,\n asyncHandler(async (req, res) => {\n const itemId = Number(req.params.id);\n const accountId = req.account!.id;","replace":" \"/api/items/:id/buy\",\n asyncHandler(async (req, res) => {\n const itemId = Number(req.params.id);\n const accountId = req.account?.id ?? (await pool.query(`SELECT id FROM account ORDER BY id LIMIT 1`)).rows[0].id;"}]},{"id":"purchase-stock-change-is-not-broadcast--01-buying","scenario":"tracks/ecommerce/scenarios/01-buying.json","targets":["ecommerce.spec.live-state.purchase-stock.3b"],"desc":"Commit purchases without broadcasting their stock changes, breaking live stock and sold-out visibility.","file":"server/src/index.ts","edits":[{"find":" lastCatalogJson = json;\n io.emit(\"items:update\", { items: catalog });","replace":" lastCatalogJson = json;\n // mutant: changed stock is not broadcast"}]},{"id":"purchase-stock-change-is-not-broadcast--stock-limit","scenario":"tracks/ecommerce/scenarios/progression-stock-limit.json","targets":["ecommerce.spec.concurrency-safety.stock-limit.3d"],"desc":"Commit purchases without broadcasting their stock changes, breaking live stock and sold-out visibility.","file":"server/src/index.ts","edits":[{"find":" lastCatalogJson = json;\n io.emit(\"items:update\", { items: catalog });","replace":" lastCatalogJson = json;\n // mutant: changed stock is not broadcast"}]},{"id":"restock-race-records-wrong-order-total","scenario":"tracks/ecommerce/scenarios/01-restock-race.json","targets":["ecommerce.spec.concurrency-safety.restock-race.202a"],"desc":"Purchases preserve stock and visible order counts but record the wrong booked total. Native mixed-race reconciliation must reject them.","file":"server/src/index.ts","edits":[{"find":" [accountId, price]\n );","replace":" [accountId, Number(price) + 1]\n );"}]},{"id":"direct-purchase-order-total-is-offset","scenario":"tracks/ecommerce/scenarios/progression-purchasing.json","targets":["ecommerce.feature.purchasing.purchase-order.3c"],"desc":"Record a direct purchase one dollar above the stored price.","file":"server/src/index.ts","edits":[{"find":" [accountId, price]\n );","replace":" [accountId, Number(price) + 1]\n );"}]},{"id":"reload-hydrates-an-empty-cart","scenario":"tracks/ecommerce/scenarios/01-cart.json","targets":["ecommerce.spec.state-durability.cart-reload.4b"],"desc":"Return an empty cart from both reload hydration paths while preserving later live cart broadcasts.","file":"server/src/index.ts","edits":[{"find":" const state = await buildCartState(req.account!.id);\n res.json(state);","replace":" await buildCartState(req.account!.id);\n res.json({ items: [], total: 0 });"},{"find":" const cartState = await buildCartState(acc.id);\n socket.emit(\"cart:update\", cartState);","replace":" await buildCartState(acc.id);\n socket.emit(\"cart:update\", { items: [], total: 0 });"}]},{"id":"signed-out-visitors-do-not-see-reviews","scenario":"tracks/ecommerce/scenarios/01-review-visibility.json","targets":["ecommerce.feature.reviews.reviews.6a"],"desc":"Hide an item's reviews whenever the viewer is signed out.","file":"client/src/App.tsx","edits":[{"find":" {reviews.length === 0 ? (","replace":" {!account || reviews.length === 0 ? ("}]},{"id":"review-average-update-is-not-broadcast","scenario":"tracks/ecommerce/scenarios/01-review-rating-live.json","targets":["ecommerce.spec.live-state.rating.6c"],"desc":"Return the new average to the submitter but omit the live review update to other viewers.","file":"server/src/index.ts","edits":[{"find":" io.emit(\"review:update\", { itemId, reviews, average });","replace":" // mutant: other open review views do not receive the new average"}]},{"id":"admin-warehouse-view-drops-one-location","scenario":"tracks/ecommerce/scenarios/01-warehouse-admin-staff.json","targets":["ecommerce.feature.warehouse-admin.warehouse-view.7b"],"desc":"Render only 23 of the 24 item-by-warehouse stock locations.","file":"client/src/App.tsx","edits":[{"find":" {admin.locations.map((loc) => {","replace":" {admin.locations.slice(0, 23).map((loc) => {"}]},{"id":"unauthenticated-direct-purchase-uses-default-account","scenario":"tracks/ecommerce/scenarios/01-purchase-session.json","targets":["ecommerce.spec.access-control.purchase-session.101a"],"desc":"Remove purchase authentication and attribute unauthenticated requests to a default account.","file":"server/src/index.ts","edits":[{"find":" \"/api/items/:id/buy\",\n requireAuth,","replace":" \"/api/items/:id/buy\","},{"find":" const itemId = Number(req.params.id);\n const accountId = req.account!.id;\n\n const client = await pool.connect();","replace":" const itemId = Number(req.params.id);\n const accountId = req.account?.id ?? 1;\n\n const client = await pool.connect();"}]},{"id":"direct-purchase-is-attributed-to-previous-account","scenario":"tracks/ecommerce/scenarios/01-purchase-attribution.json","targets":["ecommerce.spec.access-control.purchase-attribution.102a"],"desc":"Create the direct-purchase order for the preceding account id rather than the authenticated caller.","file":"server/src/index.ts","edits":[{"find":" const itemId = Number(req.params.id);\n const accountId = req.account!.id;\n\n const client = await pool.connect();","replace":" const itemId = Number(req.params.id);\n const accountId = req.account!.id - 1;\n\n const client = await pool.connect();"}]},{"id":"direct-purchase-uses-constant-price","scenario":"tracks/ecommerce/scenarios/01-server-price.json","targets":["ecommerce.spec.transactional-integrity.server-price.104a"],"desc":"Create a direct-purchase order at a hard-coded price instead of the current stored price.","file":"server/src/index.ts","edits":[{"find":" [accountId, price]\n );","replace":" [accountId, \"1.00\"]\n );"}]},{"id":"account-state-reload-discards-session","scenario":"tracks/ecommerce/scenarios/progression-account-state-reload.json","targets":["ecommerce.spec.state-durability.account-state-recovery.105a"],"desc":"Discard the authenticated account during reload hydration, making its cart and orders unavailable.","file":"client/src/App.tsx","edits":[{"find":" setAccount(me.account);","replace":" setAccount(null);"}]},{"id":"offline-event-clears-account-state","scenario":"tracks/ecommerce/scenarios/progression-account-state-reconnect.json","targets":["ecommerce.spec.state-durability.account-state-recovery.105b"],"desc":"Treat a temporary offline event as a sign-out and clear the account and cart state.","file":"client/src/App.tsx","edits":[{"find":" useEffect(() => {\n const socket = io({ path: \"/socket.io\" });","replace":" useEffect(() => {\n const clearAccountOffline = () => {\n setAccount(null);\n setCart({ items: [], total: 0 });\n };\n window.addEventListener(\"offline\", clearAccountOffline, { once: true });\n const socket = io({ path: \"/socket.io\" });"}]},{"id":"purchase-does-not-decrement-warehouse-stock","scenario":"tracks/ecommerce/scenarios/progression-books-balance.json","targets":["ecommerce.spec.transactional-integrity.books-balance.107b"],"desc":"Create purchase orders without decrementing their selected warehouse stock row.","file":"server/src/index.ts","edits":[{"find":" UPDATE stock s SET quantity = quantity - 1\n FROM target t","replace":" UPDATE stock s SET quantity = quantity\n FROM target t"}]},{"id":"review-route-skips-purchase-eligibility","scenario":"tracks/ecommerce/scenarios/01-review-eligibility.json","targets":["ecommerce.spec.access-control.review-eligibility.108a"],"desc":"Allow review creation even when the caller has never purchased the item.","file":"server/src/index.ts","edits":[{"find":" if (purchased.rowCount === 0) {","replace":" if (false && purchased.rowCount === 0) {"}]},{"id":"only-shipped-orders-earn-review-eligibility","scenario":"tracks/ecommerce/scenarios/01-review-eligibility.json","targets":["ecommerce.spec.access-control.review-eligibility.108b","ecommerce.spec.access-control.review-eligibility.108a"],"desc":"Incorrectly require an order to be shipped before its buyer may review the item. The same restriction also rejects the required successful buyer control in 108a; it does not independently test non-buyer denial.","file":"server/src/index.ts","edits":[{"find":" WHERE o.account_id = $1 AND oi.item_id = $2 LIMIT 1`,","replace":" WHERE o.account_id = $1 AND oi.item_id = $2 AND o.status = 'shipped' LIMIT 1`,"}]},{"id":"cart-update-accepts-negative-quantity","scenario":"tracks/ecommerce/scenarios/01-cart-boundary.json","targets":["ecommerce.spec.access-control.cart-boundary.109b"],"desc":"Accept a negative cart quantity update and persist it instead of refusing the named action.","file":"server/src/index.ts","edits":[{"find":" if (!Number.isInteger(quantity) || quantity < 1) {","replace":" if (!Number.isInteger(quantity)) {"}]},{"id":"oversell-no-row-lock","scenario":"tracks/ecommerce/scenarios/01-last-unit.json","targets":["ecommerce.spec.concurrency-safety.last-unit.201a","ecommerce.spec.concurrency-safety.last-unit.201b","ecommerce.spec.concurrency-safety.last-unit.201c"],"desc":"Drop the row lock so simultaneous buyers can select the same remaining units.","file":"server/src/index.ts","edits":[{"find":" FOR UPDATE\n LIMIT 1","replace":" LIMIT 1"}]},{"id":"purchase-read-write-loses-concurrent-stock","scenario":"tracks/ecommerce/scenarios/01-restock-race.json","targets":["ecommerce.spec.concurrency-safety.restock-race.202a"],"desc":"Replace atomic stock reservation with an unlocked read and absolute write. A fixed pause widens scheduling overlap; serial purchases and restocks retain their stock effects. Concurrent reservations or restocking can lose updates.","file":"server/src/index.ts","edits":[{"find":" const decrement = await client.query(\n `WITH target AS (\n SELECT item_id, warehouse_id FROM stock\n WHERE item_id = $1 AND quantity > 0\n ORDER BY warehouse_id\n FOR UPDATE\n LIMIT 1\n )\n UPDATE stock s SET quantity = quantity - 1\n FROM target t\n WHERE s.item_id = t.item_id AND s.warehouse_id = t.warehouse_id\n RETURNING s.item_id, s.warehouse_id`,\n [itemId]\n );\n","replace":" const snapshot = await client.query(\n `SELECT item_id, warehouse_id, quantity FROM stock\n WHERE item_id = $1 AND quantity > 0 ORDER BY warehouse_id LIMIT 1`, [itemId]\n );\n // Mutant: widen the unlocked read/write window without changing serial behavior.\n await new Promise(resolve => setTimeout(resolve, 500));\n const decrement = snapshot.rowCount === 0 ? snapshot : await client.query(\n `UPDATE stock SET quantity = $3 WHERE item_id = $1 AND warehouse_id = $2\n RETURNING item_id, warehouse_id`,\n [itemId, snapshot.rows[0].warehouse_id, snapshot.rows[0].quantity - 1]\n );\n"}]},{"id":"external-stock-polling-disabled","scenario":"tracks/ecommerce/scenarios/01-external-live-sync.json","targets":["ecommerce.spec.external-data-sync.external-stock.901a"],"desc":"Stop reconciling direct database changes while the server remains online.","file":"server/src/index.ts","edits":[{"find":" broadcastCatalog().catch((err) => console.error(\"poll broadcast failed\", err));","replace":" // mutant: direct database catalog changes are never reconciled"}]},{"id":"server-restart-does-not-resynchronize-catalog","scenario":"tracks/ecommerce/scenarios/01-external-server-restart-sync.json","targets":["ecommerce.spec.external-data-sync.external-stock.901c"],"desc":"After a server restart, omit both connection-time catalog hydration and periodic authoritative reconciliation.","file":"server/src/index.ts","edits":[{"find":" const catalog = await buildCatalog();\n socket.emit(\"items:update\", { items: catalog });","replace":" // mutant: reconnecting clients retain their pre-restart catalog"},{"find":" broadcastCatalog().catch((err) => console.error(\"poll broadcast failed\", err));","replace":" // mutant: restart recovery does not reconcile authoritative catalog state"}]},{"id":"reconnect-does-not-send-current-catalog","scenario":"tracks/ecommerce/scenarios/01-external-reconnect-sync.json","targets":["ecommerce.spec.external-data-sync.external-stock.901d"],"desc":"Follow catalog changes until the browser goes offline, then ignore updates after restoration.","file":"client/src/App.tsx","edits":[{"find":" const cartObservationRef = useRef(0);\n\n function applyCartResponse","replace":" const cartObservationRef = useRef(0);\n const acceptCatalogUpdates = useRef(true);\n useEffect(() => {\n const stopCatalogRecovery = () => { acceptCatalogUpdates.current = false; };\n window.addEventListener(\"offline\", stopCatalogRecovery);\n return () => window.removeEventListener(\"offline\", stopCatalogRecovery);\n }, []);\n\n function applyCartResponse"},{"find":" socket.on(\"items:update\", (payload: { items: Item[] }) => setItems(payload.items));","replace":" socket.on(\"items:update\", (payload: { items: Item[] }) => {\n if (acceptCatalogUpdates.current) setItems(payload.items);\n });"}]},{"id":"open-review-list-ignores-live-update","scenario":"tracks/ecommerce/scenarios/progression-open-list-live.json","targets":["ecommerce.spec.live-state.open-list.902a"],"desc":"Ignore committed review updates in a detail view that is already open.","file":"client/src/App.tsx","edits":[{"find":" setItemDetail({ reviews: payload.reviews, average: payload.average });","replace":" // mutant: the already-open review list ignores committed updates"}]},{"id":"open-review-list-renders-each-review-twice","scenario":"tracks/ecommerce/scenarios/progression-open-list-live.json","targets":["ecommerce.spec.live-state.open-list.902a"],"desc":"Render every committed review twice in the already-open list.","file":"client/src/App.tsx","edits":[{"find":" reviews.map((r) => (","replace":" [...reviews, ...reviews].map((r) => ("}]},{"id":"cancel-does-not-restore-stock-feature","scenario":"tracks/ecommerce/scenarios/02-order-cancellation-core.json","targets":["ecommerce.returns-pricing.cancellation-and-return.3a"],"desc":"Cancellation commits but restores zero units to each recorded warehouse row.","file":"server/src/index.ts","edits":[{"find":" [l.item_id, l.warehouse_id, l.quantity]\n );\n }\n await refundCredit(client, orderRow.rows[0]);\n await client.query(`UPDATE orders SET status = 'cancelled' WHERE id = $1`, [orderId]);","replace":" [l.item_id, l.warehouse_id, 0]\n );\n }\n await refundCredit(client, orderRow.rows[0]);\n await client.query(`UPDATE orders SET status = 'cancelled' WHERE id = $1`, [orderId]);"}]},{"id":"cancellation-accounting-loses-stock-restoration","scenario":"tracks/ecommerce/scenarios/02-invariants.json","targets":["ecommerce.returns-pricing.refund-accounting.203a"],"desc":"Cancellation removes revenue and changes order status, but loses the original warehouse stock restoration. The native refund-accounting assertion must detect this.","file":"server/src/index.ts","edits":[{"find":" [l.item_id, l.warehouse_id, l.quantity]\n );\n }\n await refundCredit(client, orderRow.rows[0]);\n await client.query(`UPDATE orders SET status = 'cancelled' WHERE id = $1`, [orderId]);","replace":" [l.item_id, l.warehouse_id, 0]\n );\n }\n await refundCredit(client, orderRow.rows[0]);\n await client.query(`UPDATE orders SET status = 'cancelled' WHERE id = $1`, [orderId]);"}]},{"id":"cancel-does-not-restore-stock-fresh-client","scenario":"tracks/ecommerce/scenarios/02-self-contained.json","targets":["ecommerce.inventory-operations.stock-conservation.202b","ecommerce.inventory-operations.stock-conservation.202c"],"desc":"Cancellation commits but restores zero units, so a fresh client reads the persisted shortfall.","file":"server/src/index.ts","edits":[{"find":" [l.item_id, l.warehouse_id, l.quantity]\n );\n }\n await refundCredit(client, orderRow.rows[0]);\n await client.query(`UPDATE orders SET status = 'cancelled' WHERE id = $1`, [orderId]);","replace":" [l.item_id, l.warehouse_id, 0]\n );\n }\n await refundCredit(client, orderRow.rows[0]);\n await client.query(`UPDATE orders SET status = 'cancelled' WHERE id = $1`, [orderId]);"}]},{"id":"cancel-restores-stock-but-keeps-pending-status","scenario":"tracks/ecommerce/scenarios/02-order-cancellation-history.json","targets":["ecommerce.returns-pricing.cancellation-and-return.3b"],"desc":"Cancellation restores allocations but writes pending back to order history.","file":"server/src/index.ts","edits":[{"find":"await client.query(`UPDATE orders SET status = 'cancelled' WHERE id = $1`, [orderId]);","replace":"await client.query(`UPDATE orders SET status = 'pending' WHERE id = $1`, [orderId]);"}]},{"id":"operator-authorization-allows-customer-transfer","scenario":"tracks/ecommerce/scenarios/02-strengthened.json","targets":["ecommerce.operations-access.operator-authorization.201a"],"desc":"The transfer route replaces its administrator gate with ordinary authentication.","file":"server/src/index.ts","edits":[{"find":"app.post(\n \"/api/admin/transfer\",\n requireAdmin,","replace":"app.post(\n \"/api/admin/transfer\",\n requireAuth,"}]},{"id":"customer-can-ship-order-direct-1-1","scenario":"tracks/ecommerce/scenarios/02-server-actions.json","targets":["ecommerce.operations-access.operator-authorization.201c"],"desc":"The shipping route replaces its staff gate with ordinary authentication.","file":"server/src/index.ts","edits":[{"find":"app.post(\n \"/api/fulfilment/ship\",\n requireStaff,","replace":"app.post(\n \"/api/fulfilment/ship\",\n requireAuth,"}]},{"id":"customer-can-cancel-foreign-order-1-1","scenario":"tracks/ecommerce/scenarios/02-server-actions.json","targets":["ecommerce.operations-access.order-owner.204a"],"desc":"Cancellation retains authentication and pending-state validation but drops order ownership.","file":"server/src/index.ts","edits":[{"find":"app.post(\n \"/api/orders/:id/cancel\",\n requireAuth,\n asyncHandler(async (req, res) => {\n const orderId = Number(req.params.id);\n const accountId = req.account!.id;\n const client = await pool.connect();\n try {\n await client.query(\"BEGIN\");\n const orderRow = await client.query(`SELECT * FROM orders WHERE id = $1 FOR UPDATE`, [orderId]);\n if (orderRow.rowCount === 0 || orderRow.rows[0].account_id !== accountId) {","replace":"app.post(\n \"/api/orders/:id/cancel\",\n requireAuth,\n asyncHandler(async (req, res) => {\n const orderId = Number(req.params.id);\n const accountId = req.account!.id;\n const client = await pool.connect();\n try {\n await client.query(\"BEGIN\");\n const orderRow = await client.query(`SELECT * FROM orders WHERE id = $1 FOR UPDATE`, [orderId]);\n if (orderRow.rowCount === 0) {"}]},{"id":"queue-depth-lags-one-order","scenario":"tracks/ecommerce/scenarios/02-fulfilment-live.json","targets":["ecommerce.operations-access.fulfilment-queue.1a"],"desc":"The queue renders every order but its visible depth remains one behind.","file":"client/src/App.tsx","edits":[{"find":"{queue.depth}","replace":"{Math.max(0, queue.depth - 1)}"}]},{"id":"customer-sees-fulfilment-navigation","scenario":"tracks/ecommerce/scenarios/02-features.json","targets":["ecommerce.operations-access.fulfilment-queue.1d"],"desc":"Expose the protected staff area to signed-in customers, including its navigation and content.","file":"client/src/App.tsx","edits":[{"find":" {account && (account.isStaff || account.isAdmin) && (\n
)}","replace":"
)}"}]},{"id":"purchase-does-not-broadcast-fulfilment-queue","scenario":"tracks/ecommerce/scenarios/02-fulfilment-live.json","targets":["ecommerce.spec.live-state.fulfilment-queue.1a"],"desc":"A direct purchase commits its pending order but omits the fulfilment queue broadcast, so an open staff queue never learns about the new order.","file":"server/src/index.ts","edits":[{"find":" await broadcastCatalog();\n await broadcastOrders(accountId);\n await broadcastFulfilment();\n await broadcastRecommended(accountId);\n res.json({ ok: true });\n })\n);\n\n// ---------- cart routes ----------","replace":" await broadcastCatalog();\n await broadcastOrders(accountId);\n // mutant: the new pending order is not pushed to open fulfilment queues\n await broadcastRecommended(accountId);\n res.json({ ok: true });\n })\n);\n\n// ---------- cart routes ----------"}]},{"id":"admin-state-change-is-not-broadcast","scenario":"tracks/ecommerce/scenarios/02-low-stock.json","targets":["ecommerce.spec.live-state.inventory-dashboard.5a"],"desc":"Changed admin dashboard state is never broadcast to open admin views, so a customer purchase that drops an item to ten units does not re-enter the low-stock list live.","file":"server/src/index.ts","edits":[{"find":" lastAdminJson = adminJson;\n io.to(\"admin\").emit(\"admin:update\", adminState);","replace":" lastAdminJson = adminJson;\n // mutant: changed admin state is not broadcast"}]},{"id":"admin-sockets-do-not-join-admin-room","scenario":"tracks/ecommerce/scenarios/02-operational-category-totals.json","targets":["ecommerce.spec.live-state.sales-dashboard.5b"],"desc":"Admin sockets receive their dashboard state on connection but never join the admin room, so a customer purchase does not update the open category totals live.","file":"server/src/index.ts","edits":[{"find":" if (acc.isAdmin) socket.join(\"admin\");","replace":" // mutant: admin sockets never join the admin room"}]},{"id":"transfer-overdraft-guard-skips-bulk-transfers","scenario":"tracks/ecommerce/scenarios/02-transfer-overdraw.json","targets":["ecommerce.spec.transactional-integrity.stock-transfer-overdraw.2c"],"desc":"The insufficient-stock guard is only evaluated for transfers under 1000 units, so a bulk transfer that overdraws the source warehouse commits instead of being refused.","file":"server/src/index.ts","edits":[{"find":" if (available < qty) {","replace":" if (available < qty && qty < 1000) {"}]},{"id":"transfer-does-not-publish-warehouse-totals","scenario":"tracks/ecommerce/scenarios/02-transfer-totals.json","targets":["ecommerce.spec.live-state.stock-transfers.2b"],"desc":"A transfer commits but answers with the pre-transfer admin snapshot and admin state is never broadcast, so the open warehouse totals do not move.","file":"server/src/index.ts","edits":[{"find":" const client = await pool.connect();\n try {\n await client.query(\"BEGIN\");\n // Lock both warehouse rows","replace":" const state = await buildAdminState();\n const client = await pool.connect();\n try {\n await client.query(\"BEGIN\");\n // Lock both warehouse rows"},{"find":" await broadcastCatalog();\n const state = await buildAdminState();\n res.json(state);\n })\n);\n\napp.post(\n \"/api/admin/price\",","replace":" await broadcastCatalog();\n res.json(state);\n })\n);\n\napp.post(\n \"/api/admin/price\","},{"find":" lastAdminJson = adminJson;\n io.to(\"admin\").emit(\"admin:update\", adminState);","replace":" lastAdminJson = adminJson;\n // mutant: changed admin state is not broadcast"}]},{"id":"credit-checkout-ignores-wallet","desc":"A credit checkout pays entirely externally despite available credit.","scenario":"tracks/ecommerce/scenarios/progression-store-credit.json","targets":["ecommerce.feature.store-credit.store-credit-750.750a"],"file":"server/src/credit.ts","edits":[{"find":" const creditMinor = Math.min(Number(account.rows[0].credit_minor), totalMinor);","replace":" const creditMinor = 0;"}]},{"id":"credit-grant-replay-increments-balance","desc":"Replaying a grant applies its credit to the wallet again.","scenario":"tracks/ecommerce/scenarios/progression-store-credit.json","targets":["ecommerce.spec.store-credit.production-752.752a"],"file":"server/src/credit.ts","edits":[{"find":" if (!existing.rows.length) {","replace":" if (existing.rows.length) await client.query('UPDATE account SET credit_minor=credit_minor+$1 WHERE id=$2', [amountMinor, accountId]);\n if (!existing.rows.length) {"}]},{"id":"customer-can-grant-credit","desc":"Customer authentication is accepted without staff authorization.","scenario":"tracks/ecommerce/scenarios/progression-store-credit.json","targets":["ecommerce.spec.store-credit.production-753.753a"],"file":"server/src/credit.ts","edits":[{"find":" app.post('/api/staff/credit', auth, staff, async (req, res) => {","replace":" app.post('/api/staff/credit', auth, async (req, res) => {"}]},{"id":"split-refund-does-not-restore-credit","desc":"The refund is recorded but its original wallet credit is not restored.","scenario":"tracks/ecommerce/scenarios/progression-split-tender-refunds.json","targets":["ecommerce.feature.split-tender-refunds.split-tender-refunds-751.751a"],"file":"server/src/progression.ts","edits":[{"find":" await refundCredit(client, order.rows[0]);","replace":" // mutant: omit wallet restoration"}]},{"id":"split-refund-duplicates-credit","desc":"A refund credits the wallet twice while recording one refund.","scenario":"tracks/ecommerce/scenarios/progression-split-tender-refunds.json","targets":["ecommerce.spec.split-tender-refunds.production-756.756a"],"file":"server/src/credit.ts","edits":[{"find":"[delta, order.account_id]);","replace":"[delta * 2, order.account_id]);"}]},{"id":"subscription-skips-due-purchase","desc":"Due deliveries are recorded as skipped although stock is available.","scenario":"tracks/ecommerce/scenarios/progression-subscriptions.json","targets":["ecommerce.feature.subscriptions.subscriptions-760.760a"],"file":"server/src/subscriptions.ts","edits":[{"find":" if (stock.rows.reduce((sum, row) => sum + row.quantity, 0) >= subscription.quantity) {","replace":" if (false && stock.rows.reduce((sum, row) => sum + row.quantity, 0) >= subscription.quantity) {"}]},{"id":"subscription-allows-foreign-cancellation","desc":"A customer can cancel another customer subscription.","scenario":"tracks/ecommerce/scenarios/progression-subscriptions.json","targets":["ecommerce.spec.subscriptions.production-762.762a"],"file":"server/src/subscriptions.ts","edits":[{"find":" if (!row || row.account_id !== req.account!.id) {","replace":" if (!row) {"}]},{"id":"subscription-pause-is-not-recorded","desc":"Pause acknowledges the request but the subscription remains active.","scenario":"tracks/ecommerce/scenarios/progression-subscriptions.json","targets":["ecommerce.spec.subscriptions.production-763.763a"],"file":"server/src/subscriptions.ts","edits":[{"find":"UPDATE purchase_subscription SET status='paused',paused_at=now() WHERE id=$1","replace":"UPDATE purchase_subscription SET status='active',paused_at=now() WHERE id=$1"}]},{"id":"credit-checkout-retains-purchased-cart","scenario":"tracks/ecommerce/scenarios/progression-store-credit.json","targets":["ecommerce.spec.store-credit.production-754.754a"],"desc":"The purchased cart remains available instead of being consumed by checkout.","file":"server/src/progression.ts","edits":[{"find":" await client.query(`DELETE FROM cart_item WHERE cart_id = $1`, [cart.rows[0].id]);","replace":" // Mutation: keep checked-out cart lines."}]},{"id":"pending-subscriptions-are-cleared-at-startup","desc":"Restart erases pending subscription work while preserving ordinary timer execution.","file":"server/src/subscriptions.ts","scenario":"tracks/ecommerce/scenarios/progression-subscriptions.json","targets":["ecommerce.spec.subscriptions.production-761.761a"],"edits":[{"find":" `);\n}\n\nexport function registerSubscriptions","replace":" `);\n await pool.query(\"UPDATE purchase_subscription SET status='cancelled' WHERE status='active'\");\n}\n\nexport function registerSubscriptions"}]},{"id":"credit-balance-is-cleared-at-startup","desc":"Restart clears an issued wallet balance while leaving accounts present.","file":"server/src/credit.ts","scenario":"tracks/ecommerce/scenarios/progression-store-credit.json","targets":["ecommerce.spec.store-credit.production-755.755a"],"edits":[{"find":" `);\n}\n\nexport async function spendCredit","replace":" `);\n await pool.query(\"UPDATE account SET credit_minor=0\");\n}\n\nexport async function spendCredit"}]},{"id":"bundle-definition-loses-component-quantity","scenario":"tracks/ecommerce/scenarios/progression-product-bundles.json","targets":["ecommerce.feature.product-bundles.product-bundles.740a"],"desc":"definition loses component quantity","file":"server/src/bundles.ts","edits":[{"find":"values.push({ ...component, itemId: item.rows[0].id });","replace":"values.push({ ...component, quantity: 1, itemId: item.rows[0].id });"}]},{"id":"bundle-catalog-write-allows-customers","scenario":"tracks/ecommerce/scenarios/progression-product-bundles.json","targets":["ecommerce.spec.bundle-integrity.bundle-743.743a"],"desc":"catalog write allows customers","file":"server/src/bundles.ts","edits":[{"find":"if (!actor?.is_admin && actor?.staff_role !== 'catalog')","replace":"if (false)"}]},{"id":"bundle-checkout-price-not-snapshot","scenario":"tracks/ecommerce/scenarios/progression-bundle-checkout.json","targets":["ecommerce.feature.bundle-checkout.bundle-checkout.741a"],"desc":"checkout price not snapshot","file":"server/src/bundles.ts","edits":[{"find":"[cart.rows[0].id, bundleId, bundle.price, JSON.stringify(allocations), JSON.stringify(bundle.bundle_components)]","replace":"[cart.rows[0].id, bundleId, bundle.price + 1, JSON.stringify(allocations), JSON.stringify(bundle.bundle_components)]"}]},{"id":"bundle-expiry-does-not-release-components","scenario":"tracks/ecommerce/scenarios/progression-bundle-checkout.json","targets":["ecommerce.spec.bundle-integrity.bundle-746.746a"],"desc":"expiry does not release components","file":"server/src/progression.ts","edits":[{"find":"await releaseBundle(client, bundle.rows[0].component_allocations);","replace":"/* mutant: component holds leak after expiration */"}]},{"id":"bundle-return-loses-original-components","scenario":"tracks/ecommerce/scenarios/progression-bundle-returns.json","targets":["ecommerce.feature.bundle-returns.bundle-returns.742a"],"desc":"return loses original components","file":"server/src/bundles.ts","edits":[{"find":"await releaseBundle(client, line.component_allocations);","replace":"/* mutant: purchased components are not restored */"}]},{"id":"bundle-return-replay-restocks-again","scenario":"tracks/ecommerce/scenarios/progression-bundle-returns.json","targets":["ecommerce.spec.bundle-integrity.bundle-742.742b"],"desc":"return replay restocks again","file":"server/src/bundles.ts","edits":[{"find":"WHERE order_id=$1 AND is_bundle AND NOT returned FOR UPDATE","replace":"WHERE order_id=$1 AND is_bundle FOR UPDATE"}]},{"id":"bundle-return-crosses-account-boundary","scenario":"tracks/ecommerce/scenarios/progression-bundle-returns.json","targets":["ecommerce.spec.bundle-integrity.bundle-748.748a"],"desc":"return crosses account boundary","file":"server/src/bundles.ts","edits":[{"find":"WHERE id=$1 AND account_id=$2 AND status IN ('shipped','delivered')","replace":"WHERE id=$1 AND $2::integer=$2::integer AND status IN ('shipped','delivered')"}]},{"id":"bundle-components-can-overdraw","scenario":"tracks/ecommerce/scenarios/progression-bundle-checkout.json","targets":["ecommerce.spec.bundle-integrity.bundle-744.744a","ecommerce.spec.bundle-integrity.bundle-745.745a"],"desc":"components can overdraw","file":"server/src/bundles.ts","edits":[{"find":"if (rows.rows.reduce((sum, row) => sum + row.quantity, 0) < component.quantity) throw new Error('A component is unavailable');","replace":"// mutant: incomplete component reservation is accepted"}]},{"id":"bundle-checkout-reuses-reservation","scenario":"tracks/ecommerce/scenarios/progression-bundle-checkout.json","targets":["ecommerce.spec.bundle-integrity.bundle-747.747a"],"desc":"checkout reuses reservation","file":"server/src/progression.ts","edits":[{"find":"await client.query(`DELETE FROM cart_item WHERE cart_id = $1`, [cart.rows[0].id]);","replace":"// mutant: cart survives checkout"}]},{"id":"return-after-support-refund-is-blocked","scenario":"tracks/ecommerce/scenarios/progression-support-return-interaction.json","targets":["ecommerce.feature.split-tender-refunds.return-refund-interaction.757a"],"desc":"Reject a valid physical return after a financial refund.","file":"server/src/index.ts","edits":[{"find":" if (lineRow.rows[0].returned) {","replace":" if (lineRow.rows[0].returned || Number(orderRow.rows[0].refund_total) > 0) {"}]},{"id":"support-refund-after-return-pays-twice","scenario":"tracks/ecommerce/scenarios/progression-support-return-interaction.json","targets":["ecommerce.feature.split-tender-refunds.return-refund-interaction.757b"],"desc":"Pay the full order again after a physical return.","file":"server/src/progression.ts","edits":[{"find":" await client.query(`UPDATE orders SET refund_total = total, status = CASE","replace":" await client.query(`UPDATE orders SET refund_total = refund_total + total, status = CASE"}]},{"id":"progression-support-history-anonymous-leak","scenario":"tracks/ecommerce/scenarios/progression-support-history.json","targets":["ecommerce.spec.access-control.support-history-logout.612d"],"desc":"Return private support subjects to signed-out visitors while preserving authenticated ownership filtering.","file":"server/src/progression.ts","edits":[{"find":" if (!account) return [];\n const where = account.isAdmin || account.isStaff ? \"TRUE\" : \"sc.account_id = $1\";\n const values = account.isAdmin || account.isStaff ? [] : [account.id];","replace":" const where = !account || account.isAdmin || account.isStaff ? \"TRUE\" : \"sc.account_id = $1\";\n const values = !account || account.isAdmin || account.isStaff ? [] : [account.id];"}]},{"id":"checkout-crash-integrity","scenario":"tracks/ecommerce/scenarios/progression-checkout-crash.json","targets":["ecommerce.spec.state-durability.checkout-crash-integrity.910a"],"desc":"A lifecycle callback changes a prepared or cleared cart to quantity two, leaving neither a legal rollback nor a complete checkout.","file":"server/src/index.ts","edits":[{"find":" await initializeProgressionSchema(pool);","replace":" await initializeProgressionSchema(pool);\n await pool.query(`INSERT INTO cart_item (cart_id, item_id, quantity) SELECT c.id, MIN(oi.item_id), 2 FROM cart c JOIN orders o ON o.account_id=c.account_id JOIN order_item oi ON oi.order_id=o.id GROUP BY c.id ON CONFLICT (cart_id,item_id) DO UPDATE SET quantity=2`);"}]},{"id":"checkout-crash-durability","scenario":"tracks/ecommerce/scenarios/progression-checkout-crash.json","targets":["ecommerce.spec.state-durability.checkout-crash-durability.910b"],"desc":"A lifecycle callback corrupts earlier order totals. The unchanged prepared snapshots and acknowledged baseline must expose the damage.","file":"server/src/index.ts","edits":[{"find":" await initializeProgressionSchema(pool);","replace":" await initializeProgressionSchema(pool);\n await pool.query('UPDATE orders SET total=0');"}]},{"id":"review-script-unsafe-render","scenario":"tracks/ecommerce/scenarios/progression-review-script.json","targets":["ecommerce.progression.review-access-specifications.stored-review-script.9180a"],"desc":"Render stored review text as HTML so it executes in another customer session.","file":"client/src/App.tsx","edits":[{"find":"
{r.comment}
","replace":"
"}]},{"id":"review-script-reject-all","scenario":"tracks/ecommerce/scenarios/progression-review-script.json","targets":["ecommerce.progression.review-access-specifications.stored-review-script.9180a"],"desc":"Reject all nonempty reviews, including the required benign review; absence of script is insufficient.","file":"server/src/index.ts","edits":[{"find":"const { rating, comment } = req.body ?? {};","replace":"const { rating, comment } = req.body ?? {};\n if (String(comment).length > 0) { res.status(400).json({ error: \"Review rejected\" }); return; }"}]},{"id":"review-owner-trust-username","scenario":"tracks/ecommerce/scenarios/progression-review-access.json","targets":["ecommerce.progression.review-access-specifications.review-eligibility-direct.618a"],"desc":"Trust the submitted buyer username instead of the authenticated caller.","file":"server/src/index.ts","edits":[{"find":"\"/api/items/:id/reviews\",\n requireAuth,\n asyncHandler(async (req, res) => {\n const itemId = Number(req.params.id);\n const accountId = req.account!.id;","replace":"\"/api/items/:id/reviews\",\n requireAuth,\n asyncHandler(async (req, res) => {\n const itemId = Number(req.params.id);\n const accountId = req.body?.username ? (await pool.query(\"SELECT id FROM account WHERE username = $1\", [req.body.username])).rows[0]?.id : req.account!.id;"}]},{"id":"review-owner-deny-after-write","scenario":"tracks/ecommerce/scenarios/progression-review-access.json","targets":["ecommerce.progression.review-access-specifications.review-eligibility-direct.618a"],"desc":"Replace the buyer review under a forged username, then return a refusal.","file":"server/src/index.ts","edits":[{"find":"\"/api/items/:id/reviews\",\n requireAuth,\n asyncHandler(async (req, res) => {\n const itemId = Number(req.params.id);\n const accountId = req.account!.id;","replace":"\"/api/items/:id/reviews\",\n requireAuth,\n asyncHandler(async (req, res) => {\n const itemId = Number(req.params.id);\n const accountId = req.body?.username ? (await pool.query(\"SELECT id FROM account WHERE username = $1\", [req.body.username])).rows[0]?.id : req.account!.id;"},{"find":"const { reviews, average } = await buildItemReviews(itemId);\n io.emit(\"review:update\", { itemId, reviews, average });","replace":"if (req.body?.username) { res.status(403).json({ error: \"Refused after write\" }); return; }\n const { reviews, average } = await buildItemReviews(itemId);\n io.emit(\"review:update\", { itemId, reviews, average });"}]},{"id":"review-owner-reject-all","scenario":"tracks/ecommerce/scenarios/progression-review-access.json","targets":["ecommerce.progression.review-access-specifications.review-eligibility-direct.618a"],"desc":"Reject the legitimate buyer review as well as unauthorized reviews.","file":"server/src/index.ts","edits":[{"find":"const { rating, comment } = req.body ?? {};","replace":"const { rating, comment } = req.body ?? {};\n if (String(comment).length > 0) { res.status(403).json({ error: \"Reject all reviews\" }); return; }"}]}]},"spacetime":{"schemaVersion":3,"fixtureSha256":"7ba1f548e89f461b95b5caf843b0fbcf2b81278428d02869d7f47e1a199eaf6e","backend":"spacetime","track":"ecommerce","note":"Mutation definitions for the SpacetimeDB ecommerce reference.","mutations":[{"id":"recommendation-dismissal-lost-on-reconnect","scenario":"tracks/ecommerce/scenarios/progression-recommendation-feedback.json","targets":["ecommerce.spec.state-durability.recommendation-feedback-restart.504c"],"desc":"Erase saved recommendation dismissals when a browser reconnects. This controls reconnect persistence, not backend restart alone.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"export const onConnect = spacetimedb.clientConnected((_ctx) => {});","replace":"export const onConnect = spacetimedb.clientConnected((ctx) => { for (const row of ctx.db.recommendationDismissal.iter()) ctx.db.recommendationDismissal.id.delete(row.id); });"}]},{"id":"pending-order-item-return-accepted","scenario":"tracks/ecommerce/scenarios/progression-order-return-boundary.json","targets":["ecommerce.returns-pricing.cancellation-and-return.3f"],"desc":"Accept a pending order return and restore its stock before shipment.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"if (!['shipped', 'delivered'].includes(order.status)) throw new SenderError('Order has not shipped yet.');","replace":"if (!['pending', 'shipped', 'delivered'].includes(order.status)) throw new SenderError('Order has not shipped yet.');"}]},{"id":"staff-admin-access-survives-role-removal","scenario":"tracks/ecommerce/scenarios/progression-staff-roles.json","targets":["ecommerce.spec.access-control.staff-role-revocation.621d"],"desc":"Keep administrator access after changing the assigned role back to staff.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"ctx.db.account.id.update({ ...target, isAdmin: role === 'admin' });","replace":"ctx.db.account.id.update({ ...target, isAdmin: target.isAdmin || role === 'admin' });"}]},{"id":"shipping-counts-sale-twice","scenario":"tracks/ecommerce/scenarios/progression-shipping-accounting.json","targets":["ecommerce.inventory-operations.shipping-accounting.202e"],"desc":"Shipping succeeds but doubles the completed sale value in authoritative revenue.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" ctx.db.customerOrder.id.update({ ...order, status: 'shipped' });","replace":" ctx.db.customerOrder.id.update({ ...order, status: 'shipped', total: order.total * 2 });"}]},{"id":"restock-client-snapshot-overwrites-concurrent-purchases","scenario":"tracks/ecommerce/scenarios/01-restock-race.json","targets":["ecommerce.spec.concurrency-safety.restock-race.202a"],"desc":"Compute absolute restock quantity when the administrator edits the form and store that captured value in the reducer. A fixed 500 ms submission delay widens the stale-write window. Serial purchases and restocks still work; intervening purchases can be overwritten. This is a stale-form lost update, not a race inside an atomic reducer.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"ctx.db.stock.insert({ ...existing, quantity: existing.quantity + quantity });\n } else {\n ctx.db.stock.insert({ item_id: itemId, warehouse_id: warehouseId, quantity });\n }\n for (const alert of","replace":"ctx.db.stock.insert({ ...existing, quantity });\n } else {\n ctx.db.stock.insert({ item_id: itemId, warehouse_id: warehouseId, quantity });\n }\n for (const alert of"},{"file":"client/src/components/AdminPanel.tsx","find":"onChange={(e) => setRestockInputs((v) => ({ ...v, [k]: e.target.value }))}","replace":"onChange={(e) => setRestockInputs((v) => ({ ...v, [k]: String(stockOf(item.id, wh.id) + Number(e.target.value)) }))}"},{"file":"client/src/App.tsx","find":" await conn?.reducers.adminRestock({ itemId, warehouseId, quantity });","replace":" // Mutant: widen the stale form submission window without changing serial behavior.\n await new Promise(resolve => setTimeout(resolve, 500));\n await conn?.reducers.adminRestock({ itemId, warehouseId, quantity });"}]},{"id":"signup-binds-the-new-account-to-the-admin-session","scenario":"tracks/ecommerce/scenarios/01-account-create.json","targets":["ecommerce.feature.accounts.accounts.1a"],"desc":"Create the requested account but bind the new browser session to the administrator, so account creation no longer signs the visitor in as the account it created.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" const acc = ctx.db.account.insert({\n id: 0n,\n username: uname,\n passwordHash: hashPassword(password),\n isAdmin: false,\n isStaff: false,\n });\n\n const existingSession = ctx.db.session.identity.find(ctx.sender);\n if (existingSession) {\n ctx.db.session.identity.update({ ...existingSession, accountId: acc.id });\n } else {\n ctx.db.session.insert({ identity: ctx.sender, accountId: acc.id });\n }","replace":" const acc = ctx.db.account.insert({\n id: 0n,\n username: uname,\n passwordHash: hashPassword(password),\n isAdmin: false,\n isStaff: false,\n });\n\n const signedInAccount = ctx.db.account.username.find('admin') ?? acc;\n const existingSession = ctx.db.session.identity.find(ctx.sender);\n if (existingSession) {\n ctx.db.session.identity.update({ ...existingSession, accountId: signedInAccount.id });\n } else {\n ctx.db.session.insert({ identity: ctx.sender, accountId: signedInAccount.id });\n }"}]},{"id":"duplicate-signup-is-silently-ignored","scenario":"tracks/ecommerce/scenarios/01-account-duplicate.json","targets":["ecommerce.feature.accounts.accounts.1b"],"desc":"Return success for a taken username without creating a session or surfacing the required refusal.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" if (existing) throw new SenderError('That username is already taken.');","replace":" if (existing) return; // mutant: duplicate signup is silently accepted"}]},{"id":"signin-does-not-verify-the-password","scenario":"tracks/ecommerce/scenarios/01-account-password.json","targets":["ecommerce.feature.accounts.accounts.1c"],"desc":"Accept a known username without comparing the supplied password hash.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" if (!acc || acc.passwordHash !== hashPassword(password)) {","replace":" if (!acc) {"}]},{"id":"signout-keeps-the-account-session","scenario":"tracks/ecommerce/scenarios/01-account-signout.json","targets":["ecommerce.feature.accounts.accounts.1d"],"desc":"Leave the current account session in place when the visitor signs out.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" if (existingSession) ctx.db.session.identity.delete(ctx.sender);","replace":" // mutant: sign out keeps the current account session"}]},{"id":"session-token-is-not-persisted-for-reload","scenario":"tracks/ecommerce/scenarios/01-account-reload.json","targets":["ecommerce.spec.state-durability.session-reload.1e"],"desc":"Discard the connection token instead of persisting it, so a reload receives a new identity with no account session.","file":"client/src/App.tsx","edits":[{"find":" if (token) localStorage.setItem('auth_token', token);","replace":" if (token) localStorage.removeItem('auth_token');"}]},{"id":"catalog-seeds-the-wrong-air-purifier-price","scenario":"tracks/ecommerce/scenarios/01-catalog-values.json","targets":["ecommerce.feature.catalog.catalog-values.2a"],"desc":"Seed Air Purifier with an incorrect stored price while leaving the rest of the catalog intact.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" ['Air Purifier', 189.0, 60, 40, 'Home'],","replace":" ['Air Purifier', 999.0, 60, 40, 'Home'],"}]},{"id":"catalog-tie-breaks-in-reverse-alphabetical-order--01-catalog-ranking","scenario":"tracks/ecommerce/scenarios/01-catalog-ranking.json","targets":["ecommerce.feature.catalog.catalog-ranking.2b"],"desc":"Reverse the specified alphabetical tie-breaker. This necessarily breaks both the initial sequence and the post-purchase sequence in the same scenario.","file":"client/src/App.tsx","edits":[{"find":" return a.name.localeCompare(b.name);","replace":" return b.name.localeCompare(a.name);"}]},{"id":"catalog-tie-breaks-in-reverse-alphabetical-order--01-core","scenario":"tracks/ecommerce/scenarios/01-core.json","targets":["ecommerce.spec.live-state.ranking.2c"],"desc":"Reverse the specified alphabetical tie-breaker. This necessarily breaks both the initial sequence and the post-purchase sequence in the same scenario.","file":"client/src/App.tsx","edits":[{"find":" return a.name.localeCompare(b.name);","replace":" return b.name.localeCompare(a.name);"}]},{"id":"purchase-does-not-update-ranking-count","scenario":"tracks/ecommerce/scenarios/01-core.json","targets":["ecommerce.spec.live-state.ranking.2c"],"desc":"Complete the purchase but leave its popularity count unchanged, so open storefronts cannot rank the purchased item first.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" bumpPurchaseCount(ctx, itemId, quantity);","replace":" // mutant: buy-now never advances the ranking count"}]},{"id":"signed-out-purchase-bypasses-account-check","scenario":"tracks/ecommerce/scenarios/progression-signed-out-purchase.json","targets":["ecommerce.spec.access-control.signed-out-purchase.3a"],"desc":"Expose the guest purchase button and accept its purchase as the existing administrator. The stock observation then exercises the broken account boundary; normal signed-in purchases remain unchanged.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"export const buyNow = spacetimedb.reducer({ itemId: t.u64() }, (ctx, { itemId }) => {\n const acc = requireAccount(ctx);","replace":"export const buyNow = spacetimedb.reducer({ itemId: t.u64() }, (ctx, { itemId }) => {\n const acc = getAccountId(ctx) === null ? ctx.db.account.username.find('admin')! : requireAccount(ctx);"},{"file":"client/src/components/ItemCard.tsx","find":" {isSignedIn && (","replace":" {true && ("}]},{"id":"buy-now-creates-orders-without-reserving-stock--01-buying","scenario":"tracks/ecommerce/scenarios/01-buying.json","targets":["ecommerce.spec.live-state.purchase-stock.3b"],"desc":"Create purchase orders without reserving inventory. The same defect necessarily breaks live purchase stock and the sell-out portion of the stock-limit check.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" const allocations = decrementStockTracked(ctx, itemId, quantity);","replace":" const allocations: Array<{ warehouseId: bigint; quantity: number }> = [];"}]},{"id":"buy-now-creates-orders-without-reserving-stock--stock-limit","scenario":"tracks/ecommerce/scenarios/progression-stock-limit.json","targets":["ecommerce.spec.concurrency-safety.stock-limit.3d"],"desc":"Create purchase orders without reserving inventory. The same defect necessarily breaks live purchase stock and the sell-out portion of the stock-limit check.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" const allocations = decrementStockTracked(ctx, itemId, quantity);","replace":" const allocations: Array<{ warehouseId: bigint; quantity: number }> = [];"}]},{"id":"restock-race-records-wrong-order-total","scenario":"tracks/ecommerce/scenarios/01-restock-race.json","targets":["ecommerce.spec.concurrency-safety.restock-race.202a"],"desc":"Purchases preserve stock and visible order counts but record the wrong booked total. Native mixed-race reconciliation must reject them.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" total: Math.round(price * 100) * quantity / 100,\n status: 'pending',","replace":" total: Math.round(price * 100) * quantity / 100 + 1,\n status: 'pending',"}]},{"id":"buy-now-records-the-wrong-order-total","scenario":"tracks/ecommerce/scenarios/progression-purchasing.json","targets":["ecommerce.feature.purchasing.purchase-order.3c"],"desc":"Record a completed buy-now order one dollar above the stored item price.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" total: Math.round(price * 100) * quantity / 100,\n status: 'pending',","replace":" total: Math.round(price * 100) * quantity / 100 + 1,\n status: 'pending',"}]},{"id":"existing-cart-line-does-not-increment-basic-cart","scenario":"tracks/ecommerce/scenarios/progression-cart-checkout.json","targets":["ecommerce.feature.cart-checkout.cart.4a"],"desc":"Write an existing cart line back without incrementing its quantity.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"ctx.db.cartItem.id.update({ ...existing, quantity: existing.quantity + 1 });","replace":"ctx.db.cartItem.id.update({ ...existing, quantity: existing.quantity });"}]},{"id":"cart-is-deleted-when-owner-disconnects","scenario":"tracks/ecommerce/scenarios/01-cart.json","targets":["ecommerce.spec.state-durability.cart-reload.4b"],"desc":"Delete the account cart on transport disconnect. Reload loses stored cart contents even after the same account signs in again; account and session records remain intact.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"export const onDisconnect = spacetimedb.clientDisconnected((_ctx) => {});","replace":"export const onDisconnect = spacetimedb.clientDisconnected((ctx) => {\n const accountId = getAccountId(ctx);\n if (accountId !== null) for (const row of [...ctx.db.cartItem.byAccountItem.filter(accountId)]) ctx.db.cartItem.id.delete(row.id);\n});"}]},{"id":"signin-binds-the-second-client-to-a-different-account","scenario":"tracks/ecommerce/scenarios/01-cart.json","targets":["ecommerce.spec.live-state.shared-cart.4c"],"desc":"Authenticate valid credentials but bind the second connection to the administrator account, so two sessions for one customer do not share the customer's cart.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" const existingSession = ctx.db.session.identity.find(ctx.sender);\n if (existingSession) {\n ctx.db.session.identity.update({ ...existingSession, accountId: acc.id });\n } else {\n ctx.db.session.insert({ identity: ctx.sender, accountId: acc.id });\n }\n }\n);\n\nexport const signOut","replace":" const wrongAccount = ctx.db.account.username.find('admin') ?? acc;\n const existingSession = ctx.db.session.identity.find(ctx.sender);\n if (existingSession) {\n ctx.db.session.identity.update({ ...existingSession, accountId: wrongAccount.id });\n } else {\n ctx.db.session.insert({ identity: ctx.sender, accountId: wrongAccount.id });\n }\n }\n);\n\nexport const signOut"}]},{"id":"checkout-does-not-empty-the-basic-cart","scenario":"tracks/ecommerce/scenarios/progression-cart-checkout.json","targets":["ecommerce.feature.cart-checkout.cart.4d"],"desc":"Leave completed checkout lines in the durable cart.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" for (const line of lines) ctx.db.cartItem.id.delete(line.id);","replace":" // mutant: checked-out cart lines remain"}]},{"id":"new-review-is-accepted-without-being-stored","scenario":"tracks/ecommerce/scenarios/01-review-visibility.json","targets":["ecommerce.feature.reviews.reviews.6a"],"desc":"Accept an eligible new review but omit its durable insert, so neither author nor visitor can see it.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" ctx.db.review.insert({\n id: 0n,\n itemId,\n accountId: acc.id,\n rating,\n comment,\n createdAt: ctx.timestamp,\n });","replace":" // mutant: accepted review is not persisted"}]},{"id":"repeat-review-inserts-a-second-row","scenario":"tracks/ecommerce/scenarios/01-review-uniqueness.json","targets":["ecommerce.spec.transactional-integrity.unique-review.6b"],"desc":"Insert a second review row instead of updating the customer's existing item review.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" ctx.db.review.id.update({ ...existing, rating, comment, createdAt: ctx.timestamp });","replace":" ctx.db.review.insert({ id: 0n, itemId, accountId: acc.id, rating, comment, createdAt: ctx.timestamp });"}]},{"id":"review-average-counts-rows-instead-of-ratings","scenario":"tracks/ecommerce/scenarios/01-review-rating-live.json","targets":["ecommerce.spec.live-state.rating.6c"],"desc":"Compute the live average from a constant per row rather than each stored rating.","file":"client/src/components/ItemDetail.tsx","edits":[{"find":" : reviews.reduce((sum, r) => sum + r.rating, 0) / reviews.length;","replace":" : reviews.reduce((sum) => sum + 1, 0) / reviews.length;"}]},{"id":"every-signed-in-customer-is-treated-as-an-admin","scenario":"tracks/ecommerce/scenarios/01-warehouse-admin-staff.json","targets":["ecommerce.spec.access-control.warehouse-area-boundary.7a"],"desc":"Use account presence instead of the server-provided administrator flag to expose the admin area.","file":"client/src/App.tsx","edits":[{"find":" const isAdmin = currentUser?.isAdmin ?? false;","replace":" const isAdmin = isSignedIn;"}]},{"id":"warehouse-view-omits-west","scenario":"tracks/ecommerce/scenarios/01-warehouse-admin-staff.json","targets":["ecommerce.feature.warehouse-admin.warehouse-view.7b"],"desc":"Filter one real warehouse out of the administrator's inventory view.","file":"client/src/App.tsx","edits":[{"find":" warehouses={warehouses}","replace":" warehouses={warehouses.filter((warehouse) => warehouse.name !== 'West')}"}]},{"id":"guest-purchase-falls-back-to-the-admin-account","scenario":"tracks/ecommerce/scenarios/01-purchase-session.json","targets":["ecommerce.spec.access-control.purchase-session.101a"],"desc":"Allow an unauthenticated direct purchase by attributing missing sessions to the administrator account, while preserving the authorized control path.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"export const buyNow = spacetimedb.reducer({ itemId: t.u64() }, (ctx, { itemId }) => {\n const acc = requireAccount(ctx);","replace":"export const buyNow = spacetimedb.reducer({ itemId: t.u64() }, (ctx, { itemId }) => {\n const accountId = getAccountId(ctx);\n const acc = (accountId === null ? null : ctx.db.account.id.find(accountId))\n ?? ctx.db.account.username.find('admin')!;"}]},{"id":"direct-purchases-are-attributed-to-the-system-account","scenario":"tracks/ecommerce/scenarios/01-purchase-attribution.json","targets":["ecommerce.spec.access-control.purchase-attribution.102a"],"desc":"Store every buy-now order under the administrator instead of the authenticated caller.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" accountId,\n createdAt: ctx.timestamp,\n total: Math.round(price * 100) * quantity / 100,","replace":" accountId: ctx.db.account.username.find('admin')!.id,\n createdAt: ctx.timestamp,\n total: Math.round(price * 100) * quantity / 100,"}]},{"id":"direct-restock-does-not-require-an-admin","scenario":"tracks/ecommerce/scenarios/01-admin-write-staff.json","targets":["ecommerce.spec.access-control.warehouse-write-boundary.103b"],"desc":"Remove the server-side administrator check from the restock reducer.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"export const adminRestock = spacetimedb.reducer(\n { itemId: t.u64(), warehouseId: t.u64(), quantity: t.u32() },\n (ctx, { itemId, warehouseId, quantity }) => {\n requireAdmin(ctx);","replace":"export const adminRestock = spacetimedb.reducer(\n { itemId: t.u64(), warehouseId: t.u64(), quantity: t.u32() },\n (ctx, { itemId, warehouseId, quantity }) => {\n // mutant: no administrator check"}]},{"id":"direct-purchase-ignores-the-stored-price","scenario":"tracks/ecommerce/scenarios/01-server-price.json","targets":["ecommerce.spec.transactional-integrity.server-price.104a"],"desc":"Create the direct purchase order one dollar above the authoritative stored price.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" total: Math.round(price * 100) * quantity / 100,\n status: 'pending',","replace":" total: 1,\n status: 'pending',"}]},{"id":"account-state-token-is-not-restored-after-reload","scenario":"tracks/ecommerce/scenarios/progression-account-state-reload.json","targets":["ecommerce.spec.state-durability.account-state-recovery.105a"],"desc":"Build a reload connection without the durable identity token, losing the account and its data.","file":"client/src/main.tsx","edits":[{"find":".withToken(localStorage.getItem('auth_token') || undefined)","replace":".withToken(undefined)"}]},{"id":"reconnect-discards-the-visible-account-state","scenario":"tracks/ecommerce/scenarios/progression-account-state-reconnect.json","targets":["ecommerce.spec.state-durability.account-state-recovery.105b"],"desc":"Keep normal reload recovery but discard the client account projection when the browser comes back online.","file":"client/src/App.tsx","edits":[{"find":" const currentUser = currentUserRows[0] ?? null;","replace":" const [discardAccountAfterReconnect, setDiscardAccountAfterReconnect] = useState(false);\n useEffect(() => {\n const discardAccount = () => setDiscardAccountAfterReconnect(true);\n window.addEventListener('online', discardAccount);\n return () => window.removeEventListener('online', discardAccount);\n }, []);\n const currentUser = discardAccountAfterReconnect ? null : currentUserRows[0] ?? null;"}]},{"id":"order-views-return-every-customers-orders","scenario":"tracks/ecommerce/scenarios/01-order-ownership.json","targets":["ecommerce.spec.access-control.order-ownership.106a"],"desc":"Remove account filters from both order views, exposing another customer's order and its line items.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" const rows = [...ctx.db.customerOrder.accountId.filter(accountId)];","replace":" const rows = [...ctx.db.customerOrder.iter()];"},{"find":" for (const o of ctx.db.customerOrder.accountId.filter(accountId)) {","replace":" for (const o of ctx.db.customerOrder.iter()) {"}]},{"id":"admin-revenue-double-counts-every-order","scenario":"tracks/ecommerce/scenarios/progression-books-balance.json","targets":["ecommerce.spec.transactional-integrity.books-balance.107a"],"desc":"Count every completed order twice in the administrator revenue projection.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" total += o.total - o.refundedTotal;","replace":" total += (o.total - o.refundedTotal) * 2;"}]},{"id":"purchases-do-not-leave-the-warehouses","scenario":"tracks/ecommerce/scenarios/progression-books-balance.json","targets":["ecommerce.spec.transactional-integrity.books-balance.107b"],"desc":"Create normal orders and revenue while leaving warehouse stock unchanged.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" const allocations = decrementStockTracked(ctx, itemId, quantity);","replace":" const allocations: Array<{ warehouseId: bigint; quantity: number }> = [];"}]},{"id":"review-purchase-eligibility-is-not-checked","scenario":"tracks/ecommerce/scenarios/01-review-eligibility.json","targets":["ecommerce.spec.access-control.review-eligibility.108a"],"desc":"Allow a signed-in customer to review an item with no matching purchase.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" if (!bought) throw new SenderError('You can only review items you have purchased.');","replace":" // mutant: purchase eligibility is not checked"}]},{"id":"eligible-review-is-accepted-without-being-stored","scenario":"tracks/ecommerce/scenarios/01-review-eligibility.json","targets":["ecommerce.spec.access-control.review-eligibility.108b","ecommerce.spec.access-control.review-eligibility.108a"],"desc":"Keep the non-buyer refusal but omit the insert for a buyer's eligible new review. Both eligibility criteria require a successfully stored eligible review as a positive control; this does not establish a non-buyer authorization defect.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" ctx.db.review.insert({\n id: 0n,\n itemId,\n accountId: acc.id,\n rating,\n comment,\n createdAt: ctx.timestamp,\n });","replace":" // mutant: eligible review is acknowledged but not persisted"}]},{"id":"cart-line-lookup-ignores-cart-ownership","scenario":"tracks/ecommerce/scenarios/01-cart-boundary.json","targets":["ecommerce.spec.access-control.cart-boundary.109a"],"desc":"Find an existing cart line by item alone, so the same named add action from another customer increments the owner's line instead of that customer's cart.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"function findCartLine(ctx: Ctx, accountId: bigint, itemId: bigint) {\n for (const row of ctx.db.cartItem.byAccountItem.filter([accountId, itemId])) {\n return row;\n }\n return null;\n}","replace":"function findCartLine(ctx: Ctx, _accountId: bigint, itemId: bigint) {\n for (const row of ctx.db.cartItem.iter()) {\n if (row.itemId === itemId) return row;\n }\n return null;\n}"}]},{"id":"purchase-does-not-reserve-stock-last-unit","scenario":"tracks/ecommerce/scenarios/01-last-unit.json","targets":["ecommerce.spec.concurrency-safety.last-unit.201a","ecommerce.spec.concurrency-safety.last-unit.201b","ecommerce.spec.concurrency-safety.last-unit.201c"],"desc":"Create purchase orders without reserving stock, proving the focused last-unit stock, order-count, and revenue consequences.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" const allocations = decrementStockTracked(ctx, itemId, quantity);","replace":" const allocations: Array<{ warehouseId: bigint; quantity: number }> = [];"}]},{"id":"existing-cart-line-does-not-increment","scenario":"tracks/ecommerce/scenarios/01-duplicate-checkout.json","targets":["ecommerce.spec.concurrency-safety.duplicate-checkout.203a"],"desc":"Render the old cart quantity after concurrent adds.","file":"client/src/components/CartPanel.tsx","edits":[{"find":" value={line.quantity}","replace":" value={1}"}]},{"id":"checkout-does-not-empty-cart","scenario":"tracks/ecommerce/scenarios/01-duplicate-checkout.json","targets":["ecommerce.spec.concurrency-safety.duplicate-checkout.203b"],"desc":"Keep checked-out cart lines so the next serialized checkout creates a duplicate order.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" for (const line of lines) ctx.db.cartItem.id.delete(line.id);","replace":" // mutant: checked-out lines remain in the cart"}]},{"id":"stock-subscription-snapshotted-once","scenario":"tracks/ecommerce/scenarios/01-external-live-sync.json","targets":["ecommerce.spec.external-data-sync.external-stock.901a"],"desc":"Render the first non-empty stock snapshot forever instead of following committed subscription updates.","file":"client/src/App.tsx","edits":[{"find":"import { useEffect, useMemo, useState } from 'react';","replace":"import { useEffect, useMemo, useRef, useState } from 'react';"},{"find":" const [stocks] = useTable(tables.stock);","replace":" const [liveStocks] = useTable(tables.stock);\n const initialStocks = useRef(null);\n if (initialStocks.current === null && liveStocks.length > 0) {\n initialStocks.current = liveStocks;\n }\n const stocks = initialStocks.current ?? liveStocks;"}]},{"id":"stock-view-ignores-update-across-app-server-stop","scenario":"tracks/ecommerce/scenarios/01-external-server-restart-sync.json","targets":["ecommerce.spec.external-data-sync.external-stock.901c"],"desc":"Persist the first stock quantities in browser session storage and keep rendering them after app-server restart, including any frontend reload. Initial stock remains correct. This validates the stale-view oracle, not SpacetimeDB storage durability.","file":"client/src/App.tsx","edits":[{"find":" const [stocks] = useTable(tables.stock);","replace":" const [liveStocks] = useTable(tables.stock);\n const cacheKey = 'stale-stock-quantities';\n let savedQuantities = sessionStorage.getItem(cacheKey);\n if (!savedQuantities && liveStocks.length > 0) {\n savedQuantities = JSON.stringify(Object.fromEntries(liveStocks.map(row => [`${row.itemId}-${row.warehouseId}`, row.quantity])));\n sessionStorage.setItem(cacheKey, savedQuantities);\n }\n const quantities: Record = JSON.parse(savedQuantities ?? '{}');\n const stocks = liveStocks.map(row => ({ ...row, quantity: quantities[`${row.itemId}-${row.warehouseId}`] ?? row.quantity }));"}]},{"id":"stock-view-keeps-pre-reconnect-snapshot","scenario":"tracks/ecommerce/scenarios/01-external-reconnect-sync.json","targets":["ecommerce.spec.external-data-sync.external-stock.901d"],"desc":"Continue following stock until the browser goes offline, then retain the last online snapshot after network restoration.","file":"client/src/App.tsx","edits":[{"find":"import { useEffect, useMemo, useState } from 'react';","replace":"import { useEffect, useMemo, useRef, useState } from 'react';"},{"find":" const [stocks] = useTable(tables.stock);","replace":" const [liveStocks] = useTable(tables.stock);\n const [freezeStockAfterOffline, setFreezeStockAfterOffline] = useState(false);\n const lastOnlineStocks = useRef(liveStocks);\n useEffect(() => {\n const freezeStock = () => setFreezeStockAfterOffline(true);\n window.addEventListener('offline', freezeStock);\n return () => window.removeEventListener('offline', freezeStock);\n }, []);\n if (!freezeStockAfterOffline) {\n lastOnlineStocks.current = liveStocks;\n }\n const stocks = freezeStockAfterOffline ? lastOnlineStocks.current : liveStocks;"}]},{"id":"open-review-list-snapshots-on-selection","scenario":"tracks/ecommerce/scenarios/progression-open-list-live.json","targets":["ecommerce.spec.live-state.open-list.902a"],"desc":"Snapshot the selected item's reviews when the detail opens instead of following later subscription updates.","file":"client/src/App.tsx","edits":[{"find":"import { useEffect, useMemo, useState } from 'react';","replace":"import { useEffect, useMemo, useRef, useState } from 'react';"},{"find":" const selectedItemReviews = selectedItemId !== null ? reviewsByItem.get(selectedItemId) ?? [] : [];","replace":" const openedReviewItem = useRef(null);\n const openedReviews = useRef<(typeof reviews)[number][]>([]);\n if (selectedItemId !== openedReviewItem.current) {\n openedReviewItem.current = selectedItemId;\n openedReviews.current = selectedItemId !== null ? reviewsByItem.get(selectedItemId) ?? [] : [];\n }\n const selectedItemReviews = openedReviews.current;"}]},{"id":"open-review-list-renders-each-review-twice","scenario":"tracks/ecommerce/scenarios/progression-open-list-live.json","targets":["ecommerce.spec.live-state.open-list.902a"],"desc":"Render every committed review twice in the already-open list.","file":"client/src/components/ItemDetail.tsx","edits":[{"find":" {reviews.map((r) => (","replace":" {[...reviews, ...reviews].map((r) => ("}]},{"id":"cancel-does-not-restore-stock-feature","scenario":"tracks/ecommerce/scenarios/02-order-cancellation-core.json","targets":["ecommerce.returns-pricing.cancellation-and-return.3a"],"desc":"The serialized cancellation reducer changes order state and purchase counts but skips allocation restoration.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" restoreOrderItemStock(ctx, li);\n decrementPurchaseCount(ctx, li.itemId, li.quantity);","replace":" // mutant: cancellation does not restore its reserved stock\n decrementPurchaseCount(ctx, li.itemId, li.quantity);"}]},{"id":"cancellation-accounting-loses-stock-restoration","scenario":"tracks/ecommerce/scenarios/02-invariants.json","targets":["ecommerce.returns-pricing.refund-accounting.203a"],"desc":"Cancellation removes revenue and changes order status, but loses the original warehouse stock restoration. The native refund-accounting assertion must detect this.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" restoreOrderItemStock(ctx, li);\n decrementPurchaseCount(ctx, li.itemId, li.quantity);","replace":" // mutant: cancellation does not restore its reserved stock\n decrementPurchaseCount(ctx, li.itemId, li.quantity);"}]},{"id":"cancel-does-not-restore-stock-fresh-client","scenario":"tracks/ecommerce/scenarios/02-self-contained.json","targets":["ecommerce.inventory-operations.stock-conservation.202b","ecommerce.inventory-operations.stock-conservation.202c"],"desc":"The serialized cancellation reducer skips allocation restoration, so a fresh client reads the persisted shortfall.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" restoreOrderItemStock(ctx, li);\n decrementPurchaseCount(ctx, li.itemId, li.quantity);","replace":" // mutant: cancellation does not restore its reserved stock\n decrementPurchaseCount(ctx, li.itemId, li.quantity);"}]},{"id":"cancel-restores-stock-but-keeps-pending-status","scenario":"tracks/ecommerce/scenarios/02-order-cancellation-history.json","targets":["ecommerce.returns-pricing.cancellation-and-return.3b"],"desc":"The serialized cancellation reducer restores allocations but writes pending back to order history.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" ctx.db.customerOrder.id.update({ ...order, status: 'cancelled' });","replace":" ctx.db.customerOrder.id.update({ ...order, status: 'pending' });"}]},{"id":"cancelled-order-remains-in-revenue-feature","scenario":"tracks/ecommerce/scenarios/02-order-cancellation-core.json","targets":["ecommerce.returns-pricing.cancellation-and-return.3a"],"desc":"The admin revenue view includes cancelled orders even though cancellation otherwise succeeds.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" if (!isOrderCounted(o)) continue;\n total += o.total - o.refundedTotal;","replace":" total += o.total - o.refundedTotal;"}]},{"id":"cancelled-order-remains-in-revenue-invariant","scenario":"tracks/ecommerce/scenarios/02-invariants.json","targets":["ecommerce.returns-pricing.refund-accounting.203a"],"desc":"The admin revenue view includes cancelled orders even though cancellation otherwise succeeds.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" if (!isOrderCounted(o)) continue;\n total += o.total - o.refundedTotal;","replace":" total += o.total - o.refundedTotal;"}]},{"id":"operator-authorization-allows-customer-transfer","scenario":"tracks/ecommerce/scenarios/02-strengthened.json","targets":["ecommerce.operations-access.operator-authorization.201a"],"desc":"The transfer reducer drops its administrator role gate.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" (ctx, { itemId, fromWarehouseId, toWarehouseId, quantity }) => {\n requireAdmin(ctx);","replace":" (ctx, { itemId, fromWarehouseId, toWarehouseId, quantity }) => {\n // mutant: no administrator role check"}]},{"id":"customer-can-ship-order-direct-1-1","scenario":"tracks/ecommerce/scenarios/02-server-actions.json","targets":["ecommerce.operations-access.operator-authorization.201c"],"desc":"The shipping reducer drops its staff role check while retaining pending-state validation.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"export const shipOrder = spacetimedb.reducer({ orderId: t.u64() }, (ctx, { orderId }) => {\n requireStaffOrAdmin(ctx);","replace":"export const shipOrder = spacetimedb.reducer({ orderId: t.u64() }, (ctx, { orderId }) => {\n // mutant: no staff role check"}]},{"id":"customer-can-cancel-foreign-order-1-1","scenario":"tracks/ecommerce/scenarios/02-server-actions.json","targets":["ecommerce.operations-access.order-owner.204a"],"desc":"Cancellation bypasses the owner helper while retaining missing-order and pending-state validation.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"export const cancelOrder = spacetimedb.reducer({ orderId: t.u64() }, (ctx, { orderId }) => {\n const order = requireOrderOwner(ctx, orderId);","replace":"export const cancelOrder = spacetimedb.reducer({ orderId: t.u64() }, (ctx, { orderId }) => {\n const order = ctx.db.customerOrder.id.find(orderId);\n if (!order) throw new SenderError('Order not found.');"}]},{"id":"queue-depth-lags-one-order","scenario":"tracks/ecommerce/scenarios/02-fulfilment-live.json","targets":["ecommerce.operations-access.fulfilment-queue.1a"],"desc":"The reactive queue renders every order but its visible depth remains one behind.","file":"client/src/components/FulfilmentPanel.tsx","edits":[{"find":"Waiting: {queue.length}","replace":"Waiting: {Math.max(0, queue.length - 1)}"}]},{"id":"ship-acknowledges-without-changing-status","scenario":"tracks/ecommerce/scenarios/02-fulfilment-ship.json","targets":["ecommerce.operations-access.fulfilment-queue.1c"],"desc":"The serialized shipping reducer accepts the call but writes pending back to the order.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" ctx.db.customerOrder.id.update({ ...order, status: 'shipped' });","replace":" ctx.db.customerOrder.id.update({ ...order, status: 'pending' });"}]},{"id":"customer-sees-fulfilment-navigation","scenario":"tracks/ecommerce/scenarios/02-features.json","targets":["ecommerce.operations-access.fulfilment-queue.1d"],"desc":"Expose the protected staff area to signed-in customers, including its navigation and content.","file":"client/src/App.tsx","edits":[{"find":" const isStaff = currentUser?.isStaff ?? false;","replace":" const isStaff = isSignedIn;"}]},{"id":"progression-customer-sees-fulfilment-content","scenario":"tracks/ecommerce/scenarios/02-fulfilment-access.json","targets":["ecommerce.spec.access-control.fulfilment-area-boundary.1d"],"desc":"Expose the protected staff area to signed-in customers, including its navigation and content.","file":"client/src/App.tsx","edits":[{"find":" const isStaff = currentUser?.isStaff ?? false;","replace":" const isStaff = isSignedIn;"}]},{"id":"operator-authorization-allows-customer-shipping","scenario":"tracks/ecommerce/scenarios/02-server-actions.json","targets":["ecommerce.operations-access.operator-authorization.201c"],"desc":"The shipping reducer drops the staff role check while retaining the pending-order guard.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"export const shipOrder = spacetimedb.reducer({ orderId: t.u64() }, (ctx, { orderId }) => {\n requireStaffOrAdmin(ctx);","replace":"export const shipOrder = spacetimedb.reducer({ orderId: t.u64() }, (ctx, { orderId }) => {\n // mutant: no staff role check"}]},{"id":"transfer-debits-source-without-crediting-existing-destination","scenario":"tracks/ecommerce/scenarios/02-strengthened.json","targets":["ecommerce.inventory-operations.stock-conservation.202a","ecommerce.inventory-operations.warehouse-transfer.2a","ecommerce.operations-access.operator-authorization.201a"],"desc":"A transfer debits the source row but writes the existing destination quantity back unchanged, violating both directional movement and total conservation inside the serialized reducer. It also breaks 201a's authorized-transfer positive control; that coupled failure is not independent evidence of an authorization defect.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" ctx.db.stock.insert({ ...toRow, quantity: toRow.quantity + quantity });","replace":" ctx.db.stock.insert({ ...toRow, quantity: toRow.quantity });"}]},{"id":"transfer-warehouse-totals-omit-destination-credit","scenario":"tracks/ecommerce/scenarios/02-transfer-totals.json","targets":["ecommerce.inventory-operations.warehouse-transfer.2b"],"desc":"The serialized transfer debits the source but writes the existing destination quantity back unchanged.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" ctx.db.stock.insert({ ...toRow, quantity: toRow.quantity + quantity });","replace":" ctx.db.stock.insert({ ...toRow, quantity: toRow.quantity });"}]},{"id":"transfer-overdraft-guard-removed","scenario":"tracks/ecommerce/scenarios/02-transfer-overdraw.json","targets":["ecommerce.inventory-operations.warehouse-transfer.2c"],"desc":"The serialized reducer no longer rejects insufficient source stock and commits negative source quantity.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" if (available < quantity) {\n throw new SenderError(`Not enough stock in source warehouse: only ${available} available.`);\n }","replace":" // mutant: insufficient source stock is not rejected"}]},{"id":"low-stock-excludes-boundary-ten","scenario":"tracks/ecommerce/scenarios/02-low-stock.json","targets":["ecommerce.inventory-operations.operational-views.5a"],"desc":"The reactive low-stock view uses a strict boundary and omits items with exactly ten units.","file":"client/src/App.tsx","edits":[{"find":" .filter((i) => (stockByItem.get(i.id) ?? 0) <= LOW_STOCK_THRESHOLD)","replace":" .filter((i) => (stockByItem.get(i.id) ?? 0) < LOW_STOCK_THRESHOLD)"}]},{"id":"category-totals-ignore-pending-purchases","scenario":"tracks/ecommerce/scenarios/02-operational-category-totals.json","targets":["ecommerce.inventory-operations.operational-views.5b"],"desc":"The category totals view includes only shipped orders, so a newly accepted pending purchase is absent.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" for (const order of ctx.db.customerOrder.iter()) {\n if (!isOrderCounted(order)) continue;","replace":" for (const order of ctx.db.customerOrder.iter()) {\n if (order.status !== 'shipped') continue;"}]},{"id":"recommendations-ignore-pending-purchases","scenario":"tracks/ecommerce/scenarios/02-operational-recommendations.json","targets":["ecommerce.inventory-operations.operational-views.5c"],"desc":"The personal recommendation view derives categories only from shipped orders, so a new pending purchase has no influence.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" for (const order of ctx.db.customerOrder.accountId.filter(accountId)) {\n if (!isOrderCounted(order)) continue;","replace":" for (const order of ctx.db.customerOrder.accountId.filter(accountId)) {\n if (order.status !== 'shipped') continue;"}]},{"id":"purchases-do-not-affect-best-sellers","scenario":"tracks/ecommerce/scenarios/02-operational-best-sellers.json","targets":["ecommerce.inventory-operations.operational-views.5d"],"desc":"Rank signed-out recommendations without purchase counts.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"const purchaseCountOf = (id: bigint) => ctx.db.itemStats.itemId.find(id)?.purchaseCount ?? 0;","replace":"const purchaseCountOf = (_id: bigint) => 0;"}]},{"id":"queue-warehouse-reports-west","scenario":"tracks/ecommerce/scenarios/02-queue-warehouse.json","targets":["ecommerce.operations-access.fulfilment-queue.1b"],"desc":"The queue renders West for the deterministic Desk Lamp allocation even though the order reserved stock in East.","file":"client/src/components/FulfilmentPanel.tsx","edits":[{"find":"{name}: {order.warehouseNames[i]}","replace":"{name}: West"}]},{"id":"transfer-creates-stock-during-race","scenario":"tracks/ecommerce/scenarios/02-server-actions.json","targets":["ecommerce.inventory-operations.stock-conservation.202d"],"desc":"The transfer reducer credits the destination one unit more than it debits from the source, so the item's total after a transfer racing a purchase is the starting total rather than one less. A stored conservation defect; it does not model a lost-update interleaving because SpacetimeDB reducer execution is atomically serialized.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" ctx.db.stock.insert({ ...toRow, quantity: toRow.quantity + quantity });","replace":" ctx.db.stock.insert({ ...toRow, quantity: toRow.quantity + quantity + 1 });"}]},{"id":"catalog-search-ignores-the-query","scenario":"tracks/ecommerce/scenarios/01-catalog-search.json","targets":["ecommerce.feature.catalog.catalog-search.2d"],"desc":"A non-empty catalog query filters out every product instead of matching names.","file":"client/src/App.tsx","edits":[{"find":".filter(item => !q || item.name.toLowerCase().includes(q))","replace":".filter(() => !q) // mutant: non-empty searches return no products"}]},{"id":"admin-total-stock-is-not-rendered","scenario":"tracks/ecommerce/scenarios/01-warehouse-stock-live-staff.json","targets":["ecommerce.spec.live-state.warehouse-stock.7c"],"desc":"The staff stock total always renders zero after a warehouse restock.","file":"client/src/components/AdminPanel.tsx","edits":[{"find":"{totalStockOf(item.id)}","replace":"{0}"}]},{"id":"customers-can-schedule-restocks","scenario":"tracks/ecommerce/scenarios/03-deferred-access.json","targets":["ecommerce.l3.deferred-access.scheduled-work-access.317a"],"desc":"Scheduling a restock no longer checks that the caller is an administrator.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" (ctx, input) => {\n requireAdmin(ctx);\n const itemName = input.item.trim();\n const warehouseName = input.warehouse.trim();\n const item = [...ctx.db.item].find(row => row.name === itemName);\n const warehouse = [...ctx.db.warehouse].find(row => row.name === warehouseName);","replace":" (ctx, input) => {\n // mutant: any signed-in or anonymous caller can schedule work\n const itemName = input.item.trim();\n const warehouseName = input.warehouse.trim();\n const item = [...ctx.db.item].find(row => row.name === itemName);\n const warehouse = [...ctx.db.warehouse].find(row => row.name === warehouseName);"}]},{"id":"scheduled-restock-execution-queue-is-process-local","scenario":"tracks/ecommerce/scenarios/03-deferred-durability.json","targets":["ecommerce.l3.deferred-durability.restart-survival.311a"],"desc":"Keep manual restock execution IDs only in the V8 process. Ordinary timers work, but restart loses the execution queue while pending rows remain. Isolate replacement can also lose this queue.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"export const scheduleRestock = spacetimedb.reducer(","replace":"const pendingRestockExecution = new Set();\n\nexport const scheduleRestock = spacetimedb.reducer("},{"find":" ctx.db.scheduledRestock.insert({\n id: 0n,\n itemId: item.id,\n warehouseId: warehouse.id,\n quantity: input.quantity,\n dueMicros: nowMicros(ctx) + BigInt(input.delaySeconds) * SECOND,\n status: 'pending',\n reorderRuleId: undefined,\n });","replace":" const pending = ctx.db.scheduledRestock.insert({\n id: 0n,\n itemId: item.id,\n warehouseId: warehouse.id,\n quantity: input.quantity,\n dueMicros: nowMicros(ctx) + BigInt(input.delaySeconds) * SECOND,\n status: 'pending',\n reorderRuleId: undefined,\n });\n pendingRestockExecution.add(pending.id);"},{"find":" if (pending.status !== 'pending' || pending.dueMicros > now) continue;\n restoreStock(ctx, pending.itemId, pending.warehouseId, pending.quantity);","replace":" if (pending.status !== 'pending' || pending.dueMicros > now) continue;\n if (pending.reorderRuleId === undefined && !pendingRestockExecution.delete(pending.id)) continue;\n restoreStock(ctx, pending.itemId, pending.warehouseId, pending.quantity);"}]},{"id":"reservation-is-delayed-past-the-durability-window","scenario":"tracks/ecommerce/scenarios/03-deferred-durability.json","targets":["ecommerce.l3.deferred-durability.restart-survival.314a"],"desc":"A reservation is persisted with a ten-minute lifetime instead of ninety seconds.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"const expiresMicros = nowMicros(ctx) + 90n * SECOND;","replace":"const expiresMicros = nowMicros(ctx) + 600n * SECOND;"}]},{"id":"completed-restock-remains-pending","scenario":"tracks/ecommerce/scenarios/03-deferred-integrity.json","targets":["ecommerce.l3.deferred-integrity.exactly-once.311a"],"desc":"A completed restock remains pending and is applied again by later maintenance ticks.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"ctx.db.scheduledRestock.id.update({ ...pending, status: 'complete' });","replace":"ctx.db.scheduledRestock.id.update({ ...pending, status: 'pending' });"}]},{"id":"reservation-expiry-restores-stock-twice","scenario":"tracks/ecommerce/scenarios/03-deferred-integrity.json","targets":["ecommerce.l3.deferred-integrity.stock-conservation.313a"],"desc":"Reservation expiry returns twice the quantity that was reserved.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"restoreStock(ctx, row.stockItemId || row.itemId, row.warehouseId, row.quantity);\n ctx.db.reservation.id.update({ ...row, expired: true });","replace":"restoreStock(ctx, row.stockItemId || row.itemId, row.warehouseId, row.quantity * 2);\n ctx.db.reservation.id.update({ ...row, expired: true });"}]},{"id":"checkout-takes-reserved-stock-again","scenario":"tracks/ecommerce/scenarios/03-deferred-integrity.json","targets":["ecommerce.l3.deferred-integrity.stock-conservation.314a"],"desc":"Checkout decrements stock after the cart reservation already took it.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"const allocations = held.map(row => ({ warehouseId: row.warehouseId, quantity: row.quantity, stockItemId: row.stockItemId }));\n const orderItemRow","replace":"const allocations = decrementStockTracked(ctx, p.itemId, p.quantity);\n const orderItemRow"}]},{"id":"reservation-does-not-decrement-stock","scenario":"tracks/ecommerce/scenarios/03-reservations.json","targets":["ecommerce.l3.reservations.reservations.301a"],"desc":"Creating a reservation leaves the public stock total unchanged.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"ctx.db.stock.insert({ ...row, quantity: row.quantity - allocation.quantity });","replace":"ctx.db.stock.insert({ ...row, quantity: row.quantity });"}]},{"id":"reservation-timer-is-static","scenario":"tracks/ecommerce/scenarios/03-reservations.json","targets":["ecommerce.l3.reservations.reservations.305a"],"desc":"The cart always renders ninety seconds instead of a decreasing reservation timer.","file":"client/src/components/CartPanel.tsx","edits":[{"find":"const seconds = Math.max(0, Number((reservation.expiresMicros - BigInt(Date.now()) * 1000n) / 1_000_000n));","replace":"const seconds = 90;"}]},{"id":"checkout-leaves-cart-lines","scenario":"tracks/ecommerce/scenarios/03-reservations.json","targets":["ecommerce.l3.reservations.reservations.306a"],"desc":"Checkout creates an order but leaves the purchased lines in the cart.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"for (const line of lines) ctx.db.cartItem.id.delete(line.id);","replace":"for (const line of lines) void line;"}]},{"id":"expired-reservation-is-still-marked-live","scenario":"tracks/ecommerce/scenarios/03-reservations.json","targets":["ecommerce.l3.reservations.reservations.307a"],"desc":"Expired reservations keep their live flag, so the cart does not mark them expired.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"ctx.db.reservation.id.update({ ...row, expired: true });","replace":"ctx.db.reservation.id.update({ ...row, expired: false });"}]},{"id":"renewed-reservation-expires-too-soon","scenario":"tracks/ecommerce/scenarios/03-reservations.json","targets":["ecommerce.l3.reservations.reservations.308a"],"desc":"Renewed quantities receive only a twenty-second reservation window.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"reserveUnits(ctx, accountId, itemId, quantity);","replace":"reserveUnits(ctx, accountId, itemId, quantity);\n for (const renewed of findReservations(ctx, accountId, itemId)) {\n ctx.db.reservation.id.update({ ...renewed, expiresMicros: nowMicros(ctx) + 20n * SECOND });\n }"}]},{"id":"pending-restock-timer-is-static","scenario":"tracks/ecommerce/scenarios/03-scheduled-restocks.json","targets":["ecommerce.l3.scheduled-restocks.scheduled-restocks.302a"],"desc":"The pending restock UI always renders ninety seconds instead of the server due time.","file":"client/src/components/ProgressionWorkbench.tsx","edits":[{"find":"{Math.max(0, Number((row.dueMicros - BigInt(Date.now()) * 1000n) / 1_000_000n))}","replace":"{90}"}]},{"id":"due-restock-omits-ledger-entry","scenario":"tracks/ecommerce/scenarios/03-scheduled-restock-apply.json","targets":["ecommerce.l3.scheduled-restocks.scheduled-restocks.305a"],"desc":"A due restock updates stock but does not create its stock ledger record.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"ctx.db.stockLedger.insert({\n id: 0n,\n itemId: pending.itemId,\n warehouseId: pending.warehouseId,\n quantity: pending.quantity,\n createdMicros: now,\n source: 'scheduled restock',\n });","replace":"// mutant: due restocks are not recorded in the ledger"}]},{"id":"cancelled-restock-remains-pending","scenario":"tracks/ecommerce/scenarios/03-scheduled-restock-cancel.json","targets":["ecommerce.l3.scheduled-restocks.scheduled-restocks.306a"],"desc":"Cancelling a restock leaves it pending, so maintenance later applies it.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"ctx.db.scheduledRestock.id.update({ ...row, status: 'cancelled' });","replace":"ctx.db.scheduledRestock.id.update({ ...row, status: 'pending' });"}]},{"id":"restart-restock-runs-early","scenario":"tracks/ecommerce/scenarios/03-server-time.json","targets":["ecommerce.l3.server-time.server-time.312a"],"desc":"A scheduled restock ignores its requested delay and becomes due after one second.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"dueMicros: nowMicros(ctx) + BigInt(input.delaySeconds) * SECOND,","replace":"dueMicros: nowMicros(ctx) + SECOND,"}]},{"id":"closed-browser-reservation-never-expires","scenario":"tracks/ecommerce/scenarios/03-server-time.json","targets":["ecommerce.l3.server-time.server-time.313a"],"desc":"Server maintenance skips reservation expiry when no customer browser is present.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"for (const row of [...ctx.db.reservation.iter()]) {\n if (row.expired || row.expiresMicros > now) continue;","replace":"for (const row of [...ctx.db.reservation.iter()].filter(() => false)) {\n if (row.expired || row.expiresMicros > now) continue;"}]},{"id":"catalog-product-is-not-published","scenario":"tracks/ecommerce/scenarios/progression-catalog-management.json","targets":["ecommerce.progression.catalog-management.catalog-management.622a","ecommerce.progression.catalog-management.catalog-management.622b"],"desc":"The public product card omits the submitted name. Both create visibility and variant navigation locate the submitted product card by its name, so the hidden name prevents both required observations.","file":"client/src/components/ItemCard.tsx","edits":[{"find":"{item.name}","replace":"{item.name === 'Travel Mug' ? '' : item.name}"}]},{"id":"catalog-variants-are-discarded","scenario":"tracks/ecommerce/scenarios/progression-catalog-management.json","targets":["ecommerce.progression.catalog-management.catalog-management.622b"],"desc":"Catalog management discards every submitted product variant.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"for (const variantName of variants.split(',').map(value => value.trim()).filter(Boolean)) {\n ctx.db.itemVariant.insert({ id: 0n, itemId: product.id, name: variantName });\n }","replace":"void variants; // mutant: submitted variants are discarded"}]},{"id":"profile-is-lost-on-fresh-account-login","scenario":"tracks/ecommerce/scenarios/progression-customer-profile.json","targets":["ecommerce.spec.state-durability.customer-profile-reload.620a"],"desc":"Delete a saved profile when its owner signs in from a new transport identity. Initial save, same-identity reload, and the independent privacy owner remain intact.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" throw new SenderError('Incorrect username or password.');\n }\n\n const existingSession = ctx.db.session.identity.find(ctx.sender);\n if (existingSession) {\n ctx.db.session.identity.update({ ...existingSession, accountId: acc.id });","replace":" throw new SenderError('Incorrect username or password.');\n }\n\n const existingSession = ctx.db.session.identity.find(ctx.sender);\n if (!existingSession) { ctx.db.customerProfile.accountId.delete(acc.id); }\n if (existingSession) {\n ctx.db.session.identity.update({ ...existingSession, accountId: acc.id });"}]},{"id":"customer-profile-view-leaks-another-account","scenario":"tracks/ecommerce/scenarios/progression-customer-profile.json","targets":["ecommerce.spec.access-control.customer-profile-privacy.620b"],"desc":"The customer profile view returns the first stored profile without checking its owner.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"return accountId === null ? undefined : ctx.db.customerProfile.accountId.find(accountId) ?? undefined;","replace":"return accountId === null ? undefined : [...ctx.db.customerProfile.iter()][0];"}]},{"id":"faceted-search-ignores-category","scenario":"tracks/ecommerce/scenarios/progression-faceted-filters.json","targets":["ecommerce.progression.faceted-search.faceted-search.401a"],"desc":"Faceted search applies price and stock filters but ignores the selected category.","file":"client/src/App.tsx","edits":[{"find":".filter(item => !categoryFilter || categoryByItem.get(item.id) === categoryFilter)","replace":".filter(() => true) // mutant: category filter is ignored"}]},{"id":"active-search-uses-purchase-ranking","scenario":"tracks/ecommerce/scenarios/progression-search-ordering.json","targets":["ecommerce.spec.search-ordering.search-ordering.402b"],"desc":"Keep purchase ranking when search text or filters are active.","file":"client/src/App.tsx","edits":[{"find":"const catalogItems = showingSearch ? filteredSearchResults : rankedItems;","replace":"const catalogItems = rankedItems;"}]},{"id":"faceted-search-next-page-does-not-advance","scenario":"tracks/ecommerce/scenarios/progression-faceted-pagination.json","targets":["ecommerce.progression.faceted-search.faceted-search.402a"],"desc":"The next-page control keeps the search on its current page.","file":"client/src/App.tsx","edits":[{"find":"onClick={() => setSearchPage(page => page + 1)}>Next","replace":"onClick={() => setSearchPage(page => page)}>Next"}]},{"id":"managed-support-leaks-and-accepts-cross-account-replies","scenario":"tracks/ecommerce/scenarios/progression-managed-support-privacy.json","targets":["ecommerce.spec.access-control.managed-support-privacy.613b"],"desc":"Managed support tickets are visible across accounts and replayed replies are accepted.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":".filter(row => isGuestTicketCreator(sender, row.creatorIdentity.toHexString(), row.accountId) ||\n !!actor && (actor.isAdmin || actor.isStaff || row.accountId === accountId))","replace":".filter(() => true)"},{"file":"backend/spacetimedb/src/index.ts","find":"if (!actor.isAdmin && !actor.isStaff && ticket.accountId !== actor.id) {\n throw new SenderError('That support ticket is private.');\n }","replace":"// mutant: any signed-in account can access any support ticket"}]},{"id":"managed-support-replies-are-empty","scenario":"tracks/ecommerce/scenarios/progression-managed-support-shared.json","targets":["ecommerce.spec.live-state.managed-support.613a","ecommerce.progression.managed-support.managed-support.613c"],"desc":"Managed support stores replies without their message body. Both the ordinary reply and shared-live reply assertions require the stored message body; neither can pass an empty reply.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"body: body.trim(),\n createdMicros: nowMicros(ctx),","replace":"body: '',\n createdMicros: nowMicros(ctx),"}]},{"id":"managed-support-live-replies-stay-at-initial-snapshot","scenario":"tracks/ecommerce/scenarios/progression-managed-support-shared.json","targets":["ecommerce.spec.live-state.managed-support.613a"],"desc":"Keep the initial subscribed reply snapshot on each page. Reducers still save replies, and a reload shows them, but later replies do not reach the rendered conversation live.","file":"client/src/App.tsx","edits":[{"find":" const [supportReplyRows] = useTable(tables.visibleSupportReplies);","replace":" const [liveSupportReplyRows, supportRepliesReady] = useTable(tables.visibleSupportReplies);\n const supportReplyRows = useMemo(() => [...liveSupportReplyRows], [supportRepliesReady]);"}]},{"id":"notification-preferences-are-not-saved","scenario":"tracks/ecommerce/scenarios/progression-notification-preferences.json","targets":["ecommerce.spec.state-durability.notification-preferences-reload.630a"],"desc":"Saving notification preferences discards the selected values.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"if (existing) ctx.db.notificationPreference.accountId.update(row);\n else ctx.db.notificationPreference.insert(row);","replace":"void existing;\n void row; // mutant: notification preferences are discarded"}]},{"id":"notification-preferences-leak-across-accounts","scenario":"tracks/ecommerce/scenarios/progression-notification-preferences.json","targets":["ecommerce.spec.access-control.notification-preferences-privacy.630b"],"desc":"The preference view returns another account's first stored choice.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"const row = ctx.db.notificationPreference.accountId.find(accountId);\n return row ? { orderEnabled: row.orderEnabled, stockEnabled: row.stockEnabled } : undefined;","replace":"const row = [...ctx.db.notificationPreference.iter()][0];\n return row ? { orderEnabled: row.orderEnabled, stockEnabled: row.stockEnabled } : undefined;"}]},{"id":"checkout-records-zero-payment","scenario":"tracks/ecommerce/scenarios/progression-core-business.json","targets":["ecommerce.progression.payment-records.payment-records.623a"],"desc":"Checkout records a paid payment with a zero amount.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"ctx.db.paymentRecord.insert({ id: 0n, orderId: order.id, amount: order.total, status: 'paid' });\n if (promo) {","replace":"ctx.db.paymentRecord.insert({ id: 0n, orderId: order.id, amount: 0, status: 'paid' });\n if (promo) {"}]},{"id":"checkout-records-duplicate-payments","scenario":"tracks/ecommerce/scenarios/progression-core-business.json","targets":["ecommerce.spec.transactional-integrity.payment-deduplication.623b"],"desc":"Checkout inserts two payment records for one order.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"ctx.db.paymentRecord.insert({ id: 0n, orderId: order.id, amount: order.total, status: 'paid' });\n if (promo) {","replace":"ctx.db.paymentRecord.insert({ id: 0n, orderId: order.id, amount: order.total, status: 'paid' });\n ctx.db.paymentRecord.insert({ id: 0n, orderId: order.id, amount: order.total + 0.01, status: 'paid' });\n if (promo) {"}]},{"id":"active-promotion-does-not-discount-checkout","scenario":"tracks/ecommerce/scenarios/progression-promotion-checkout.json","targets":["ecommerce.progression.promotion-checkout.promotion-checkout-active.621a"],"desc":"Checkout ignores an active promotion when it calculates the discount.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"const discount = promo ? total * (promo.discountPercent / 100) : 0;","replace":"const discount = 0;"}]},{"id":"expired-promotion-is-accepted","scenario":"tracks/ecommerce/scenarios/progression-promotion-checkout.json","targets":["ecommerce.progression.promotion-checkout.promotion-checkout-expired.621b"],"desc":"Promotion application does not reject a promotion after its end time.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"if (!promo || promo.startMicros > now || promo.endMicros < now || promo.redemptions >= promo.usageLimit) {","replace":"if (!promo || promo.startMicros > now || promo.redemptions >= promo.usageLimit) {"}]},{"id":"exhausted-promotion-is-accepted","scenario":"tracks/ecommerce/scenarios/progression-promotion-checkout.json","targets":["ecommerce.progression.promotion-checkout.promotion-checkout-exhausted.621c"],"desc":"Promotion application does not reject a promotion at its usage limit.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"if (!promo || promo.startMicros > now || promo.endMicros < now || promo.redemptions >= promo.usageLimit) {","replace":"if (!promo || promo.startMicros > now || promo.endMicros < now) {"}]},{"id":"customers-can-create-promotions","scenario":"tracks/ecommerce/scenarios/progression-promotion-rules.json","targets":["ecommerce.spec.access-control.promotion-management-boundary.620b"],"desc":"Promotion creation does not require staff access.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" (ctx, input) => {\n requireStaffOrAdmin(ctx);\n if (input.discountPercent <= 0 || input.discountPercent > 100) {","replace":" (ctx, input) => {\n if (input.discountPercent <= 0 || input.discountPercent > 100) {"}]},{"id":"promotion-rule-stores-the-wrong-discount","scenario":"tracks/ecommerce/scenarios/progression-promotion-rules.json","targets":["ecommerce.progression.promotion-rules.promotion-rule-values.620a"],"desc":"Promotion creation stores a one-percent discount instead of the submitted value.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"ctx.db.promotion.insert({ id: 0n, ...input, code: input.code.trim(), redemptions: 0 });","replace":"ctx.db.promotion.insert({ id: 0n, ...input, discountPercent: 1, code: input.code.trim(), redemptions: 0 });"}]},{"id":"staff-cannot-open-staff-tools","scenario":"tracks/ecommerce/scenarios/progression-staff-access.json","targets":["ecommerce.progression.staff-access.staff-access.601a"],"desc":"Deny administrators entry to staff tools while keeping ordinary staff access working.","file":"client/src/App.tsx","edits":[{"find":"{(isStaff || isAdmin) && (\n ({","replace":"return [...ctx.db.notification.iter()].map(row => ({"}]},{"id":"support-history-is-lost-on-fresh-account-login","scenario":"tracks/ecommerce/scenarios/progression-support-history.json","targets":["ecommerce.spec.state-durability.support-history-reload.612a"],"desc":"Resolve customer support ownership by transport identity only, omitting the account ownership path. Initial submission, same-identity reload, and stored tickets remain intact; fresh account login cannot recover the history.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"!!actor && (actor.isAdmin || actor.isStaff || row.accountId === accountId))","replace":"!!actor && (actor.isAdmin || actor.isStaff || row.creatorIdentity.toHexString() === sender))"}]},{"id":"support-history-leaks-across-customers","scenario":"tracks/ecommerce/scenarios/progression-support-history.json","targets":["ecommerce.spec.access-control.support-history-privacy.612b","ecommerce.spec.access-control.support-history-logout.612d"],"desc":"Return all support tickets, exposing them to other customers and signed-out visitors.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":".filter(row => isGuestTicketCreator(sender, row.creatorIdentity.toHexString(), row.accountId) ||\n !!actor && (actor.isAdmin || actor.isStaff || row.accountId === accountId))","replace":".filter(() => true)"}]},{"id":"visitor-support-reference-is-hidden","scenario":"tracks/ecommerce/scenarios/progression-support-intake.json","targets":["ecommerce.progression.support-intake.support-intake.610a"],"desc":"A visitor can create a support ticket but the returned reference is not rendered.","file":"client/src/components/ProgressionWorkbench.tsx","edits":[{"find":"
{supportReference}
","replace":"
"}]},{"id":"support-assignment-is-discarded","scenario":"tracks/ecommerce/scenarios/progression-support-triage.json","targets":["ecommerce.progression.support-triage.support-assignment.611a"],"desc":"Support triage saves status and priority but discards the assignee.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"ctx.db.supportTicket.id.update({ ...ticket, assigneeId: nextAssigneeId, priority, status });","replace":"ctx.db.supportTicket.id.update({ ...ticket, assigneeId: undefined, priority, status });"}]},{"id":"support-priority-is-discarded","scenario":"tracks/ecommerce/scenarios/progression-support-triage.json","targets":["ecommerce.progression.support-triage.support-priority.611b"],"desc":"Support triage always saves normal priority instead of the submitted value.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"ctx.db.supportTicket.id.update({ ...ticket, assigneeId: nextAssigneeId, priority, status });","replace":"ctx.db.supportTicket.id.update({ ...ticket, assigneeId: nextAssigneeId, priority: 'normal', status });"}]},{"id":"support-status-is-discarded","scenario":"tracks/ecommerce/scenarios/progression-support-triage.json","targets":["ecommerce.progression.support-triage.support-status.611c"],"desc":"Support triage preserves the old status instead of the submitted value.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"ctx.db.supportTicket.id.update({ ...ticket, assigneeId: nextAssigneeId, priority, status });","replace":"ctx.db.supportTicket.id.update({ ...ticket, assigneeId: nextAssigneeId, priority, status: ticket.status });"}]},{"id":"nonpositive-cart-quantity-is-treated-as-removal","scenario":"tracks/ecommerce/scenarios/01-cart-boundary.json","targets":["ecommerce.spec.access-control.cart-boundary.109b"],"desc":"Accept a negative quantity and remove the cart line instead of refusing the request.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" if (quantity < 1) throw new SenderError('Quantity must be at least 1.');\n const existing = findCartLine(ctx, acc.id, itemId);\n if (!existing) throw new SenderError('That item is not in your cart.');\n if (existing.bundlePrice > 0) throw new SenderError('Remove and re-add a whole bundle.');\n replaceReservation(ctx, acc.id, itemId, quantity);\n ctx.db.cartItem.id.update({ ...existing, quantity });","replace":" const existing = findCartLine(ctx, acc.id, itemId);\n if (!existing) throw new SenderError('That item is not in your cart.');\n if (quantity < 1) {\n ctx.db.cartItem.id.delete(existing.id);\n return;\n }\n if (existing.bundlePrice > 0) throw new SenderError('Remove and re-add a whole bundle.');\n replaceReservation(ctx, acc.id, itemId, quantity);\n ctx.db.cartItem.id.update({ ...existing, quantity });"}]},{"id":"admin-restock-preserves-existing-stock","scenario":"tracks/ecommerce/scenarios/01-warehouse-stock-live-staff.json","targets":["ecommerce.spec.live-state.warehouse-stock.7c"],"desc":"Accept an administrator restock but write the existing quantity back unchanged.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" ctx.db.stock.insert({ ...existing, quantity: existing.quantity + quantity });","replace":" ctx.db.stock.insert({ ...existing, quantity: existing.quantity });"}]},{"id":"operator-authorization-allows-customer-price-change","scenario":"tracks/ecommerce/scenarios/02-strengthened.json","targets":["ecommerce.operations-access.operator-authorization.201b"],"desc":"The price reducer drops its administrator role gate.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" (ctx, { itemId, price }) => {\n requireAdmin(ctx);","replace":" (ctx, { itemId, price }) => {\n // mutant: no administrator role check"}]},{"id":"fulfilment-queue-allows-customer-shipping","scenario":"tracks/ecommerce/scenarios/02-self-contained.json","targets":["ecommerce.operations-access.fulfilment-queue.1e"],"desc":"The shipping reducer drops the staff role check while retaining the pending-order guard.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"export const shipOrder = spacetimedb.reducer({ orderId: t.u64() }, (ctx, { orderId }) => {\n requireStaffOrAdmin(ctx);","replace":"export const shipOrder = spacetimedb.reducer({ orderId: t.u64() }, (ctx, { orderId }) => {\n // mutant: no staff role check"}]},{"id":"catalog-search-keeps-pre-change-price","scenario":"tracks/ecommerce/scenarios/02-live-price.json","targets":["ecommerce.returns-pricing.price-history.4b"],"desc":"The search result renderer caches each item's first visible price and ignores later live price updates.","file":"client/src/components/ItemCard.tsx","edits":[{"find":"import { ItemRow } from '../types';","replace":"import { useRef } from 'react';\nimport { ItemRow } from '../types';"},{"find":" const outOfStock = stock <= 0;\n const lowStock = !outOfStock && stock <= 5;","replace":" const outOfStock = stock <= 0;\n const lowStock = !outOfStock && stock <= 5;\n // mutant: the card retains the first price it renders\n const firstPrice = useRef(item.price);"},{"find":" {formatMoney(item.price)}","replace":" {formatMoney(firstPrice.current)}"}]},{"id":"open-cart-keeps-pre-change-price","scenario":"tracks/ecommerce/scenarios/progression-price-cart-checkout.json","targets":["ecommerce.returns-pricing.price-history.4c"],"desc":"The open-cart memo ignores reactive item-table price updates while checkout still reads the current server price.","file":"client/src/App.tsx","edits":[{"find":" [cartRows, items, stockByItem]","replace":" [cartRows, stockByItem]"}]},{"id":"catalog-price-rewrites-receipts","scenario":"tracks/ecommerce/scenarios/02-paid-price-history.json","targets":["ecommerce.returns-pricing.price-history.4a"],"desc":"Changing a catalog price cascades into saved order lines and recomputes historical order totals inside the reducer transaction.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" ctx.db.item.id.update({ ...it, price });","replace":" ctx.db.item.id.update({ ...it, price });\n const repricedOrderIds = new Set();\n for (const line of ctx.db.orderItem.iter()) {\n if (line.itemId !== itemId) continue;\n ctx.db.orderItem.id.update({ ...line, unitPrice: price });\n repricedOrderIds.add(line.orderId);\n }\n for (const orderId of repricedOrderIds) {\n const historical = ctx.db.customerOrder.id.find(orderId);\n if (!historical) continue;\n let total = 0;\n for (const line of ctx.db.orderItem.orderId.filter(orderId)) total += line.unitPrice * line.quantity;\n ctx.db.customerOrder.id.update({ ...historical, total });\n }"}]},{"id":"catalog-price-rewrites-earned-revenue","scenario":"tracks/ecommerce/scenarios/02-invariants.json","targets":["ecommerce.returns-pricing.refund-accounting.203b"],"desc":"Changing a catalog price cascades into saved order lines and recomputes historical order totals and revenue inside the reducer transaction.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" ctx.db.item.id.update({ ...it, price });","replace":" ctx.db.item.id.update({ ...it, price });\n const repricedOrderIds = new Set();\n for (const line of ctx.db.orderItem.iter()) {\n if (line.itemId !== itemId) continue;\n ctx.db.orderItem.id.update({ ...line, unitPrice: price });\n repricedOrderIds.add(line.orderId);\n }\n for (const orderId of repricedOrderIds) {\n const historical = ctx.db.customerOrder.id.find(orderId);\n if (!historical) continue;\n let total = 0;\n for (const line of ctx.db.orderItem.orderId.filter(orderId)) total += line.unitPrice * line.quantity;\n ctx.db.customerOrder.id.update({ ...historical, total });\n }"}]},{"id":"returned-line-marker-omitted","scenario":"tracks/ecommerce/scenarios/02-strengthened.json","targets":["ecommerce.returns-pricing.cancellation-and-return.3c"],"desc":"A returned order line keeps its persisted returned state, restored stock, and adjusted revenue but omits the visible returned marker.","file":"client/src/components/OrdersPanel.tsx","edits":[{"find":"{item.returned && Returned}","replace":"{false && Returned}"}]},{"id":"direct-review-access-is-not-checked","scenario":"tracks/ecommerce/scenarios/progression-review-access.json","targets":["ecommerce.progression.review-access-specifications.review-eligibility-direct.618a"],"desc":"The direct review action accepts a review from a customer who did not buy the item.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" if (!bought) throw new SenderError('You can only review items you have purchased.');","replace":" // mutant: purchase eligibility is not checked"}]},{"id":"support-history-rows-are-hidden","scenario":"tracks/ecommerce/scenarios/progression-support-history.json","targets":["ecommerce.progression.support-history.support-history.612c","ecommerce.spec.state-durability.support-history-reload.612a","ecommerce.spec.access-control.support-history-privacy.612b","ecommerce.spec.access-control.support-history-logout.612d"],"desc":"Hide submitted support ticket rows while leaving the submission reference available. History, reload, privacy, and logout require the owner to see the ticket first. This breaks those positive observations; it does not create a privacy leak or remove stored data.","file":"client/src/components/ProgressionWorkbench.tsx","edits":[{"find":"data-role=\"support-ticket\"","replace":"data-role=\"support-ticket\" style={{ display: \"none\" }}"}]},{"id":"authorized-restock-does-not-change-stock","scenario":"tracks/ecommerce/scenarios/01-admin-write-staff.json","targets":["ecommerce.feature.warehouse-admin.admin-write.103a"],"desc":"Accept an administrator restock without changing warehouse stock.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" if (existing) {\n ctx.db.stock.by_item_warehouse.delete([itemId, warehouseId]);\n ctx.db.stock.insert({ ...existing, quantity: existing.quantity + quantity });\n } else {\n ctx.db.stock.insert({ item_id: itemId, warehouse_id: warehouseId, quantity });\n }\n","replace":" // mutant: accept restock without changing stock\n"}]},{"id":"low-stock-threshold-is-two-units","scenario":"tracks/ecommerce/scenarios/02-low-stock.json","targets":["ecommerce.inventory-operations.operational-views.5e","ecommerce.spec.live-state.inventory-dashboard.5a"],"desc":"The dashboard lists only items with two units or fewer, so the seeded three-unit item is missing from the low-stock view. The live check in the same scenario opens with the identical observation and necessarily fails with it.","file":"client/src/App.tsx","edits":[{"find":"const LOW_STOCK_THRESHOLD = 10;","replace":"const LOW_STOCK_THRESHOLD = 2;"}]},{"id":"category-totals-count-only-since-the-dashboard-opened","scenario":"tracks/ecommerce/scenarios/02-operational-category-totals.json","targets":["ecommerce.inventory-operations.operational-views.5f"],"desc":"The category table shows units and revenue accumulated since the dashboard was opened instead of the stored totals, so a reload resets both to zero and the totals recorded before the reload are not reproduced. Live movement within one open dashboard is still correct, so the live check is unaffected.","file":"client/src/components/AdminPanel.tsx","edits":[{"find":"import { useState } from 'react';","replace":"import { useRef, useState } from 'react';"},{"find":" return (\n
","replace":" const openingTotals = useRef | null>(null);\n if (openingTotals.current === null && categoryTotals.length > 0) {\n openingTotals.current = new Map(\n categoryTotals.map((cat): [bigint, { units: number; revenue: number }] => [\n cat.categoryId,\n { units: cat.unitsSold, revenue: cat.revenue },\n ])\n );\n }\n const sessionTotals = categoryTotals.map((cat) => {\n const opening = openingTotals.current?.get(cat.categoryId);\n return {\n ...cat,\n unitsSold: cat.unitsSold - (opening?.units ?? 0),\n revenue: cat.revenue - (opening?.revenue ?? 0),\n };\n });\n\n return (\n
"},{"find":" {categoryTotals.map((cat) => (","replace":" {sessionTotals.map((cat) => ("}]},{"id":"profile-summary-ignores-a-profile-saved-this-session","scenario":"tracks/ecommerce/scenarios/progression-customer-profile.json","targets":["ecommerce.progression.customer-profile.customer-profile.620c"],"desc":"Hide the profile summary immediately after saving in the current view. Stored profile data and a reopened or reloaded view remain correct, so fresh-login durability and privacy positive controls remain observable.","file":"client/src/components/ProgressionWorkbench.tsx","edits":[{"find":" const [profileName, setProfileName] = useState(profile?.name ?? '');","replace":" const [profileName, setProfileName] = useState(profile?.name ?? '');\n const [profileSavedHere, setProfileSavedHere] = useState(false);"},{"find":"onClick={() => reducers?.saveProfile({ name: profileName, address: profileAddress })}","replace":"onClick={() => { setProfileSavedHere(true); return reducers?.saveProfile({ name: profileName, address: profileAddress }); }}"},{"find":"
{profile?.name} {profile?.address}
","replace":"
{!profileSavedHere && <>{profile?.name} {profile?.address}}
"}]},{"id":"stored-support-replies-are-hidden-after-reload","scenario":"tracks/ecommerce/scenarios/progression-managed-support-shared.json","targets":["ecommerce.progression.managed-support.managed-support.613c"],"desc":"Replies already stored when the page loads are hidden and only replies that arrive while the page is open are shown, so a reloaded customer or staff member cannot see the earlier exchange. The live shared-case check exchanges only new replies and is unaffected.","file":"client/src/App.tsx","edits":[{"find":"import { useEffect, useMemo, useState } from 'react';","replace":"import { useEffect, useMemo, useRef, useState } from 'react';"},{"find":" const [supportReplyRows] = useTable(tables.visibleSupportReplies);","replace":" const [liveSupportReplyRows, supportRepliesReady] = useTable(tables.visibleSupportReplies);\n const openedSupportReplies = useRef | null>(null);\n if (openedSupportReplies.current === null && supportRepliesReady) {\n openedSupportReplies.current = new Set(\n liveSupportReplyRows.map((row) => `${row.ticketId}:${row.author}:${row.body}`)\n );\n }\n const supportReplyRows = liveSupportReplyRows.filter(\n (row) => !openedSupportReplies.current?.has(`${row.ticketId}:${row.author}:${row.body}`)\n );"}]},{"id":"saving-notification-preferences-resets-the-toggles","scenario":"tracks/ecommerce/scenarios/progression-notification-preferences.json","targets":["ecommerce.progression.notification-preferences.notification-preferences.630c"],"desc":"Saving sends the chosen preferences but resets both toggles to off and stops the form from following the stored row for the rest of the session, so the saved choice cannot be seen until a reload. The reload and cross-account checks read the stored row on a fresh page and are unaffected.","file":"client/src/components/ProgressionWorkbench.tsx","edits":[{"find":" useEffect(() => {\n setOrderEnabled(preferences?.orderEnabled ?? false);\n setStockEnabled(preferences?.stockEnabled ?? false);\n }, [preferences?.orderEnabled, preferences?.stockEnabled]);","replace":" const [preferencesSubmitted, setPreferencesSubmitted] = useState(false);\n useEffect(() => {\n if (preferencesSubmitted) return;\n setOrderEnabled(preferences?.orderEnabled ?? false);\n setStockEnabled(preferences?.stockEnabled ?? false);\n }, [preferences?.orderEnabled, preferences?.stockEnabled, preferencesSubmitted]);"},{"find":"onClick={() => reducers?.saveNotificationPreferences({ orderEnabled, stockEnabled })}","replace":"onClick={() => { reducers?.saveNotificationPreferences({ orderEnabled, stockEnabled }); setPreferencesSubmitted(true); setOrderEnabled(false); setStockEnabled(false); }}"}]},{"id":"saving-a-staff-role-snaps-the-input-back-to-the-stored-role","scenario":"tracks/ecommerce/scenarios/progression-staff-roles.json","targets":["ecommerce.progression.staff-roles.staff-roles.621c"],"desc":"Saving a role sends the new role to the server but snaps the visible input back to the role stored before the save for the rest of the session, so the administrator cannot see the assignment take. A reload renders the stored role, so the durability and boundary checks are unaffected.","file":"client/src/components/ProgressionWorkbench.tsx","edits":[{"find":" ","replace":" "}]},{"id":"fulfilment-queue-is-frozen-at-page-load","scenario":"tracks/ecommerce/scenarios/02-fulfilment-live.json","targets":["ecommerce.spec.live-state.fulfilment-queue.1a"],"desc":"The fulfilment queue renders the rows delivered with the page's initial subscription and ignores later updates, so an order placed while the queue is open never appears without a reload.","file":"client/src/App.tsx","edits":[{"find":"import { useEffect, useMemo, useState } from 'react';","replace":"import { useEffect, useMemo, useRef, useState } from 'react';"},{"find":" const [queueRows] = useTable(tables.fulfilmentQueue);","replace":" const [liveQueueRows, queueReady] = useTable(tables.fulfilmentQueue);\n const openedQueueRows = useRef(null);\n if (openedQueueRows.current === null && queueReady) openedQueueRows.current = liveQueueRows;\n const queueRows = openedQueueRows.current ?? liveQueueRows;"}]},{"id":"low-stock-list-is-frozen-at-page-load","scenario":"tracks/ecommerce/scenarios/02-low-stock.json","targets":["ecommerce.spec.live-state.inventory-dashboard.5a"],"desc":"The low-stock list is computed once from the first complete stock snapshot and never recomputed, so items no longer enter or leave it as stock is restocked or sold. The seeded low item is in that first snapshot, so the static listing check is unaffected.","file":"client/src/App.tsx","edits":[{"find":"import { useEffect, useMemo, useState } from 'react';","replace":"import { useEffect, useMemo, useRef, useState } from 'react';"},{"find":" const lowStockItems = useMemo(\n () =>\n [...items]\n .filter((i) => (stockByItem.get(i.id) ?? 0) <= LOW_STOCK_THRESHOLD)\n .sort((a, b) => (stockByItem.get(a.id) ?? 0) - (stockByItem.get(b.id) ?? 0)),\n [items, stockByItem]\n );","replace":" const liveLowStockItems = useMemo(\n () =>\n [...items]\n .filter((i) => (stockByItem.get(i.id) ?? 0) <= LOW_STOCK_THRESHOLD)\n .sort((a, b) => (stockByItem.get(a.id) ?? 0) - (stockByItem.get(b.id) ?? 0)),\n [items, stockByItem]\n );\n const openedLowStockItems = useRef(null);\n if (openedLowStockItems.current === null && items.length > 0 && stocks.length > 0) {\n openedLowStockItems.current = liveLowStockItems;\n }\n const lowStockItems = openedLowStockItems.current ?? liveLowStockItems;"}]},{"id":"category-totals-are-frozen-at-page-load","scenario":"tracks/ecommerce/scenarios/02-operational-category-totals.json","targets":["ecommerce.spec.live-state.sales-dashboard.5b"],"desc":"The category totals render the first non-empty row set received and ignore later updates, so a purchase does not move units or revenue while the dashboard is open. A reload receives the stored totals, so the reload check is unaffected.","file":"client/src/App.tsx","edits":[{"find":"import { useEffect, useMemo, useState } from 'react';","replace":"import { useEffect, useMemo, useRef, useState } from 'react';"},{"find":" const [categoryTotalRows] = useTable(tables.categoryTotals);","replace":" const [liveCategoryTotalRows] = useTable(tables.categoryTotals);\n const openedCategoryTotalRows = useRef(null);\n if (openedCategoryTotalRows.current === null && liveCategoryTotalRows.length > 0) {\n openedCategoryTotalRows.current = liveCategoryTotalRows;\n }\n const categoryTotalRows = openedCategoryTotalRows.current ?? liveCategoryTotalRows;"}]},{"id":"warehouse-totals-are-frozen-at-page-load","scenario":"tracks/ecommerce/scenarios/02-transfer-totals.json","targets":["ecommerce.spec.live-state.stock-transfers.2b"],"desc":"The per-warehouse totals are computed once from the first stock snapshot and never recomputed, so a transfer moves neither warehouse figure while the dashboard is open.","file":"client/src/App.tsx","edits":[{"find":"import { useEffect, useMemo, useState } from 'react';","replace":"import { useEffect, useMemo, useRef, useState } from 'react';"},{"find":" const stockByWarehouse = useMemo(() => {\n const map = new Map();\n for (const row of stocks) {\n map.set(row.warehouseId, (map.get(row.warehouseId) ?? 0) + row.quantity);\n }\n return map;\n }, [stocks]);","replace":" const liveStockByWarehouse = useMemo(() => {\n const map = new Map();\n for (const row of stocks) {\n map.set(row.warehouseId, (map.get(row.warehouseId) ?? 0) + row.quantity);\n }\n return map;\n }, [stocks]);\n const openedStockByWarehouse = useRef(null);\n if (openedStockByWarehouse.current === null && liveStockByWarehouse.size > 0) {\n openedStockByWarehouse.current = liveStockByWarehouse;\n }\n const stockByWarehouse = openedStockByWarehouse.current ?? liveStockByWarehouse;"}]},{"id":"transfer-skips-the-source-holding-check","scenario":"tracks/ecommerce/scenarios/02-transfer-overdraw.json","targets":["ecommerce.spec.transactional-integrity.stock-transfer-overdraw.2c"],"desc":"The serialized transfer reducer no longer checks that the source warehouse holds the requested quantity, so an overdraw is accepted instead of refused and the source quantity wraps below zero.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" if (available < quantity) {\n throw new SenderError(`Not enough stock in source warehouse: only ${available} available.`);\n }","replace":" // mutant: the source warehouse holding is not checked"}]},{"id":"credit-checkout-ignores-wallet","desc":"A credit checkout pays entirely externally despite available credit.","scenario":"tracks/ecommerce/scenarios/progression-store-credit.json","targets":["ecommerce.feature.store-credit.store-credit-750.750a"],"file":"backend/spacetimedb/src/index.ts","edits":[{"find":" const creditMinor = useCredit ? Math.min(wallet?.amountMinor ?? 0,totalMinor) : 0;","replace":" const creditMinor = 0;"}]},{"id":"credit-grant-replay-increments-balance","desc":"Replaying a grant applies its credit to the wallet again.","scenario":"tracks/ecommerce/scenarios/progression-store-credit.json","targets":["ecommerce.spec.store-credit.production-752.752a"],"file":"backend/spacetimedb/src/index.ts","edits":[{"find":" if (existing.amountMinor !== amountMinor) throw new SenderError('Reference identifies another grant.');\n return;","replace":" if (existing.amountMinor !== amountMinor) throw new SenderError('Reference identifies another grant.');\n const wallet = ctx.db.creditWallet.accountId.find(accountId)!;\n ctx.db.creditWallet.accountId.update({ ...wallet, amountMinor: wallet.amountMinor + amountMinor });\n return;"}]},{"id":"customer-can-grant-credit","desc":"Customer authentication is accepted without staff authorization.","scenario":"tracks/ecommerce/scenarios/progression-store-credit.json","targets":["ecommerce.spec.store-credit.production-753.753a"],"file":"backend/spacetimedb/src/index.ts","edits":[{"find":" (ctx, { accountId, amountMinor, reference }) => {\n requireStaffOrAdmin(ctx);","replace":" (ctx, { accountId, amountMinor, reference }) => {\n requireAccount(ctx);"}]},{"id":"split-refund-does-not-restore-credit","desc":"The refund is recorded but its original wallet credit is not restored.","scenario":"tracks/ecommerce/scenarios/progression-split-tender-refunds.json","targets":["ecommerce.feature.split-tender-refunds.split-tender-refunds-751.751a"],"file":"backend/spacetimedb/src/index.ts","edits":[{"find":" refundOrderCredit(ctx, order, order.total);","replace":" // mutant: omit wallet restoration"}]},{"id":"split-refund-duplicates-credit","desc":"A refund credits the wallet twice while recording one refund.","scenario":"tracks/ecommerce/scenarios/progression-split-tender-refunds.json","targets":["ecommerce.spec.split-tender-refunds.production-756.756a"],"file":"backend/spacetimedb/src/index.ts","edits":[{"find":"amountMinor: wallet.amountMinor + delta","replace":"amountMinor: wallet.amountMinor + delta * 2"}]},{"id":"subscription-skips-due-purchase","desc":"Due deliveries are recorded as skipped although stock is available.","scenario":"tracks/ecommerce/scenarios/progression-subscriptions.json","targets":["ecommerce.feature.subscriptions.subscriptions-760.760a"],"file":"backend/spacetimedb/src/subscriptions.ts","edits":[{"find":" const orderId = purchase(row.accountId, row.itemId, row.quantity, row.price);","replace":" const orderId: bigint | null = null;"}]},{"id":"subscription-allows-foreign-cancellation","desc":"A customer can cancel another customer subscription.","scenario":"tracks/ecommerce/scenarios/progression-subscriptions.json","targets":["ecommerce.spec.subscriptions.production-762.762a"],"file":"backend/spacetimedb/src/subscriptions.ts","edits":[{"find":" if (!row || row.accountId !== accountId) throw new SenderError('Subscription access denied.');","replace":" if (!row) throw new SenderError('Subscription access denied.');"}]},{"id":"subscription-pause-is-not-recorded","desc":"Pause acknowledges the request but the subscription remains active.","scenario":"tracks/ecommerce/scenarios/progression-subscriptions.json","targets":["ecommerce.spec.subscriptions.production-763.763a"],"file":"backend/spacetimedb/src/subscriptions.ts","edits":[{"find":" ctx.db.purchaseSubscription.id.update({ ...row, status: 'paused', pausedMicros: now });","replace":" ctx.db.purchaseSubscription.id.update({ ...row, status: 'active', pausedMicros: now });"}]},{"id":"credit-checkout-retains-purchased-cart","scenario":"tracks/ecommerce/scenarios/progression-store-credit.json","targets":["ecommerce.spec.store-credit.production-754.754a"],"desc":"The purchased cart remains available instead of being consumed by checkout.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" for (const line of lines) ctx.db.cartItem.id.delete(line.id);","replace":" // mutant: checked-out lines remain in the cart"}]},{"id":"reconnection-erases-stored-credit","desc":"A new connection erases stored wallet credit; the fresh view after restart must catch the data loss.","file":"backend/spacetimedb/src/index.ts","scenario":"tracks/ecommerce/scenarios/progression-store-credit.json","targets":["ecommerce.spec.store-credit.production-755.755a"],"edits":[{"find":"export const onConnect = spacetimedb.clientConnected((_ctx) => {});","replace":"export const onConnect = spacetimedb.clientConnected(ctx => { for (const row of ctx.db.creditWallet.iter()) ctx.db.creditWallet.accountId.update({ ...row, amountMinor: 0 }); });"}]},{"id":"reconnection-cancels-pending-subscriptions","desc":"A new connection cancels pending subscriptions; restarting and reconnecting must preserve this work.","file":"backend/spacetimedb/src/index.ts","scenario":"tracks/ecommerce/scenarios/progression-subscriptions.json","targets":["ecommerce.spec.subscriptions.production-761.761a"],"edits":[{"find":"export const onConnect = spacetimedb.clientConnected((_ctx) => {});","replace":"export const onConnect = spacetimedb.clientConnected(ctx => { for (const row of ctx.db.purchaseSubscription.iter()) if (row.status === 'active') ctx.db.purchaseSubscription.id.update({ ...row, status: 'cancelled' }); });"}]},{"id":"bundle-definition-loses-component-quantity","scenario":"tracks/ecommerce/scenarios/progression-product-bundles.json","targets":["ecommerce.feature.product-bundles.product-bundles.740a"],"desc":"definition loses component quantity","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"return { ...component, itemId: String(product.id) };","replace":"return { ...component, quantity: 1, itemId: String(product.id) };"}]},{"id":"bundle-catalog-write-allows-customers","scenario":"tracks/ecommerce/scenarios/progression-product-bundles.json","targets":["ecommerce.spec.bundle-integrity.bundle-743.743a"],"desc":"catalog write allows customers","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"const actor = requireStaffOrAdmin(ctx);\n if (!actor.isAdmin && ctx.db.staffRole.accountId.find(actor.id)?.role !== 'catalog') {","replace":"const actor = requireAccount(ctx);\n if (false) {"}]},{"id":"bundle-checkout-price-not-snapshot","scenario":"tracks/ecommerce/scenarios/progression-bundle-checkout.json","targets":["ecommerce.feature.bundle-checkout.bundle-checkout.741a"],"desc":"checkout price not snapshot","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"bundlePrice: product.price, bundleComponentsJson: definition.componentsJson","replace":"bundlePrice: product.price + 1, bundleComponentsJson: definition.componentsJson"}]},{"id":"bundle-return-loses-original-components","scenario":"tracks/ecommerce/scenarios/progression-bundle-returns.json","targets":["ecommerce.feature.bundle-returns.bundle-returns.742a"],"desc":"return loses original components","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"for (const line of bundles) {\n restoreOrderItemStock(ctx, line);","replace":"for (const line of bundles) {\n // mutant: original stock is not restored"}]},{"id":"bundle-return-replay-restocks-again","scenario":"tracks/ecommerce/scenarios/progression-bundle-returns.json","targets":["ecommerce.spec.bundle-integrity.bundle-742.742b"],"desc":"return replay restocks again","file":"backend/spacetimedb/src/index.ts","edits":[{"find":".filter(row => row.isBundle && !row.returned);","replace":".filter(row => row.isBundle);"}]},{"id":"bundle-return-crosses-account-boundary","scenario":"tracks/ecommerce/scenarios/progression-bundle-returns.json","targets":["ecommerce.spec.bundle-integrity.bundle-748.748a"],"desc":"return crosses account boundary","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"if (!order || order.accountId !== account.id || !['shipped', 'delivered'].includes(order.status))","replace":"if (!order || !['shipped', 'delivered'].includes(order.status))"}]},{"id":"bundle-components-can-overdraw","scenario":"tracks/ecommerce/scenarios/progression-bundle-checkout.json","targets":["ecommerce.spec.bundle-integrity.bundle-744.744a","ecommerce.spec.bundle-integrity.bundle-745.745a"],"desc":"components can overdraw","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"if (!allocations) throw new SenderError('Not enough stock to reserve.');","replace":"if (!allocations) { if (bundleId) return; throw new SenderError('Not enough stock to reserve.'); }"}]},{"id":"bundle-checkout-reuses-reservation","scenario":"tracks/ecommerce/scenarios/progression-bundle-checkout.json","targets":["ecommerce.spec.bundle-integrity.bundle-747.747a"],"desc":"checkout reuses reservation","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"for (const row of held) ctx.db.reservation.id.delete(row.id);\n processReorderRules(ctx, p.itemId);","replace":"// mutant: reservations survive checkout\n processReorderRules(ctx, p.itemId);"},{"find":"for (const line of lines) ctx.db.cartItem.id.delete(line.id);","replace":"// mutant: cart survives checkout"}]},{"id":"bundle-expiry-does-not-release-components","scenario":"tracks/ecommerce/scenarios/progression-bundle-checkout.json","targets":["ecommerce.spec.bundle-integrity.bundle-746.746a"],"desc":"Expired bundle reservations retain their component stock after restart.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"if (row.expired || row.expiresMicros > now) continue;\n restoreStock(ctx, row.stockItemId || row.itemId, row.warehouseId, row.quantity);","replace":"if (row.expired || row.expiresMicros > now) continue;\n if (!row.stockItemId) restoreStock(ctx, row.itemId, row.warehouseId, row.quantity);"}]},{"id":"return-after-support-refund-is-blocked","scenario":"tracks/ecommerce/scenarios/progression-support-return-interaction.json","targets":["ecommerce.feature.split-tender-refunds.return-refund-interaction.757a"],"desc":"Reject a valid physical return after a financial refund.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" if (target.returned) throw new SenderError('Item already returned.');","replace":" if (target.returned || order.refundedTotal > 0) throw new SenderError('Item already returned.');"}]},{"id":"support-refund-after-return-pays-twice","scenario":"tracks/ecommerce/scenarios/progression-support-return-interaction.json","targets":["ecommerce.feature.split-tender-refunds.return-refund-interaction.757b"],"desc":"Pay the full order again after the physical return already refunded it.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" const amount = order.total - order.refundedTotal;","replace":" const amount = order.total;"},{"find":"refundedTotal: order.total, status: order.status","replace":"refundedTotal: order.refundedTotal + amount, status: order.status"}]},{"id":"support-history-leaks-to-signed-out-visitors","scenario":"tracks/ecommerce/scenarios/progression-support-history.json","targets":["ecommerce.spec.access-control.support-history-logout.612d"],"desc":"Disclose support tickets to signed-out visitors while leaving signed-in ownership filtering unchanged.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":".filter(row => isGuestTicketCreator(sender, row.creatorIdentity.toHexString(), row.accountId) ||","replace":".filter(row => !actor || isGuestTicketCreator(sender, row.creatorIdentity.toHexString(), row.accountId) ||"}]},{"id":"checkout-crash-integrity","scenario":"tracks/ecommerce/scenarios/progression-checkout-crash.json","targets":["ecommerce.spec.state-durability.checkout-crash-integrity.910a"],"desc":"A lifecycle callback changes a prepared or cleared cart to quantity two, leaving neither a legal rollback nor a complete checkout.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"export const onDisconnect = spacetimedb.clientDisconnected((_ctx) => {});","replace":"export const onDisconnect = spacetimedb.clientDisconnected((ctx) => { for (const row of ctx.db.cartItem.iter()) if ([...ctx.db.customerOrder.iter()].some(order => order.accountId === row.accountId)) ctx.db.cartItem.id.update({ ...row, quantity: 2 }); });"}]},{"id":"checkout-crash-durability","scenario":"tracks/ecommerce/scenarios/progression-checkout-crash.json","targets":["ecommerce.spec.state-durability.checkout-crash-durability.910b"],"desc":"A lifecycle callback corrupts earlier order totals. The unchanged prepared snapshots and acknowledged baseline must expose the damage.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"export const onDisconnect = spacetimedb.clientDisconnected((_ctx) => {});","replace":"export const onDisconnect = spacetimedb.clientDisconnected((ctx) => { for (const order of ctx.db.customerOrder.iter()) if ([...ctx.db.cartItem.iter()].some(row => row.accountId === order.accountId)) ctx.db.customerOrder.id.update({ ...order, total: 0 }); });"}]},{"id":"review-script-unsafe-render","scenario":"tracks/ecommerce/scenarios/progression-review-script.json","targets":["ecommerce.progression.review-access-specifications.stored-review-script.9180a"],"desc":"Render stored review text as HTML so it executes in another customer session.","file":"client/src/components/ItemDetail.tsx","edits":[{"find":"
{r.comment}
","replace":"
"}]},{"id":"review-script-reject-all","scenario":"tracks/ecommerce/scenarios/progression-review-script.json","targets":["ecommerce.progression.review-access-specifications.stored-review-script.9180a"],"desc":"Reject all nonempty reviews, including the required benign review; absence of script is insufficient.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"(ctx, { itemId, rating, comment }) => {","replace":"(ctx, { itemId, rating, comment }) => {\n if (comment.length > 0) throw new SenderError(\"Review rejected\");"}]},{"id":"review-owner-reject-all","scenario":"tracks/ecommerce/scenarios/progression-review-access.json","targets":["ecommerce.progression.review-access-specifications.review-eligibility-direct.618a"],"desc":"Reject the legitimate buyer review as well as unauthorized reviews.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"(ctx, { itemId, rating, comment }) => {","replace":"(ctx, { itemId, rating, comment }) => {\n if (comment.length > 0) throw new SenderError(\"Reject all reviews\");"}]}]}}} diff --git a/tools/stack-bench/qualification-evidence/ecommerce-l3-e804c1302/executable-equivalence.md b/tools/stack-bench/qualification-evidence/ecommerce-l3-e804c1302/executable-equivalence.md new file mode 100644 index 00000000000..8b0af1bb990 --- /dev/null +++ b/tools/stack-bench/qualification-evidence/ecommerce-l3-e804c1302/executable-equivalence.md @@ -0,0 +1,42 @@ +# Qualification executable equivalence + +The previous full L3 gate and the review-owner targeted gates used the frozen +controller image `sha256:6e820aeaaf9cab078d2fd64f422190922e9f29f2fc55c2833ce00f5d27243c47`. +The targeted null artifact was produced by the same image with the changed +qualification modules and explicit null-selection command mounted read-only. +All source scopes remain recorded in the original artifacts. + +The executable differences covered by this decision are confined to: +- recipe-release.ts: expose the existing meaning and execution hash inputs; + the public recipe release and its hashes are unchanged; +- calibration-compiler.ts and qualification-slices.ts: validate combined evidence + and save its definition inputs; no application action or grading assertion changes; +- reference-live.ts: save definition inputs alongside the original artifact; +- null-control.ts: select explicit checks within the calibrated selection and + save definition inputs. Selected checks use the existing grader and null analyzer. + +These imports change broad executable identities. They do not change the +underlying reference deployment, request transport, browser action, assertion, +mutation execution, reset, lease or cleanup code. The snapshot compiler verifies +hash preimages, scenario setup, shared runtime/fixture/prompt inputs, per-pack +budgets, exact control definitions, runner/reference inputs and coverage. + +The preceding check-definition change (e804c1302) is NOT declared equivalent. +Only its 113 unchanged checks are reused from the previous full gate. Check +618a uses the new targeted clean/mutation observations plus the new null gate. +All prior artifacts are retained unchanged, including their original identities +and diagnostic labels. Targeted mutation gates can supply their validated clean +baseline to the reference slice; they are never relabeled as full reference runs. + +The current implementation is limited to independent dependency scenarios with +the same qualification policy and check population. run-suite resets the app +before each selected scenario. Sequential inherited-stage reuse is rejected. +Pack timing still comes from passing observations under unchanged pack budgets; +this is not a new throughput measurement or a claim of perfect app correctness. + +Verification: 31 focused tests passed, including the actual registered evidence +and rejection cases. The final qualification-status tests passed (9/9). +Typecheck, build, four calibration checks and four definition snapshots passed. +The status command now returns ready=true with no blockers or rerun commands. +The qualification-cli.ts change only suppresses redundant launch suggestions +when this validated coverage is already complete. diff --git a/tools/stack-bench/qualification-evidence/ecommerce-l3-e804c1302/mongodb-targeted.json b/tools/stack-bench/qualification-evidence/ecommerce-l3-e804c1302/mongodb-targeted.json new file mode 100644 index 00000000000..6e139e41f4a --- /dev/null +++ b/tools/stack-bench/qualification-evidence/ecommerce-l3-e804c1302/mongodb-targeted.json @@ -0,0 +1,136 @@ +{ + "artifactSchemaVersion": 2, + "kind": "reference_qualification", + "id": "reference-live-mongodb-20260918002257-30", + "attempt": { + "id": "reference-live-mongodb-20260918002257-30", + "parentId": null + }, + "timestamps": { + "startedAt": "2026-09-18T00:22:57.158Z", + "completedAt": "2026-09-18T00:24:39.838Z" + }, + "identities": { + "engine": { + "id": "stack-bench", + "sha256": "581451119c180f50fd478aa2c17e1fa766fd38e7648e01d8a354334df1b606d3" + }, + "recipe": { + "id": "ecommerce.progression-catalog", + "sha256": "53fbb8093b2335837d88c246f04da99858c40b57ce24d17fbd2b6c815abdb62d" + }, + "fixture": { + "id": "ecommerce-reference-mongodb", + "sha256": "0d21bbc4b2768f4077a81d676f0d4c87a65067dda8f2c5ffeb2fa9208381dc7e" + }, + "calibration": { + "id": "ecommerce.dependency-l3-calibration", + "sha256": "253174720de8d80e884e764e4d8018c0a98e1c54b364b33f7679aa189af8d1bd" + }, + "experiment": null, + "agentAdapter": null, + "stackAdapter": { + "id": "mongodb", + "sha256": null + }, + "packs": [] + }, + "payload": { + "fixture": "ecommerce-reference-mongodb", + "fixtureSha256": "0d21bbc4b2768f4077a81d676f0d4c87a65067dda8f2c5ffeb2fa9208381dc7e", + "requiredRepetitions": 1, + "isolation": "docker", + "runner": { + "schemaVersion": 1, + "mode": "appliance", + "platform": "linux", + "architecture": "x64", + "hostname": "docker-desktop", + "dockerEngineVersion": "29.6.2", + "dockerOs": "linux", + "dockerArchitecture": "x86_64", + "kernelVersion": "6.6.87.2-microsoft-standard-WSL2", + "cpuCount": 32, + "memoryBytes": 49232842752, + "containersRunning": 11, + "packageRegistry": "http://127.0.0.1:4873/" + }, + "qualificationScope": { + "checksSha256": "b9d7acf0749c3310b680e9376cc4e931cf59382da420a64a4c5e2bf320e89b88", + "executableSha256": "591d84b0d1979e7ffdb6c3145f53cc7c0bf3e4441aa6a10849e1003d87b96b80", + "kind": "mutation", + "mutationSha256": "df2a358515b32488c8463eced65df967a42972cebaf9d6eed7b097212265f0af", + "recipe": { + "contentSha256": "53fbb8093b2335837d88c246f04da99858c40b57ce24d17fbd2b6c815abdb62d", + "id": "ecommerce.progression-catalog" + }, + "schemaVersion": 3, + "stack": { + "id": "mongodb", + "reference": { + "id": "ecommerce-reference-mongodb", + "sourceSha256": "0d21bbc4b2768f4077a81d676f0d4c87a65067dda8f2c5ffeb2fa9208381dc7e" + }, + "version": "1.5.0" + }, + "sha256": "1f9692823a0eba3f8b25397aad41d4ab4779f1778e9ea2158de0a6239f074c57" + }, + "mutationControl": true, + "runs": [ + { + "repetition": 1, + "output": "mongodb-targeted.runs/r1", + "durationMs": 102620, + "processError": null, + "harnessSha256Before": "8cf33debdb3c7f4797c0b324facba96dd68ca68736c60170d61f7b76f892b9e4", + "harnessSha256After": "8cf33debdb3c7f4797c0b324facba96dd68ca68736c60170d61f7b76f892b9e4", + "ok": true, + "failures": [], + "runId": "ecommerce-mongodb-run0-20260918002257-be580e5b", + "score": "2/2", + "imageId": "sha256:32ff9a9e519ba9d1af2fe72f24622caa8ca7a9f2baf2338c6b1e0435e6ac5455", + "criteria": 1, + "zeroPointCriteria": 0, + "fingerprint": "f1da4e8dbf9629a97b00bb384d6cc95f9a0005fccc9fde991cd1f69b79f8de8d", + "outcome": "passed", + "packRuntime": { + "schemaVersion": 1, + "metric": "pack-check-wall-clock-sum-v1", + "packs": [ + { + "id": "ecommerce.progression.review-access-specifications", + "checkCount": 1, + "setupRuntimeMs": 676, + "criterionRuntimeMs": 6844, + "measuredRuntimeMs": 7520, + "budget": { + "status": "bounded", + "maxRuntimeMs": 82000 + }, + "exceeded": false + } + ] + }, + "mutations": { + "caught": 4, + "completed": 4, + "total": 4, + "remaining": 0 + } + } + ], + "stable": true, + "sameImage": true, + "sameHarness": true, + "harnessSha256": "8cf33debdb3c7f4797c0b324facba96dd68ca68736c60170d61f7b76f892b9e4", + "qualifiedCheckKeys": [ + "ecommerce.progression.review-access-specifications.review-eligibility-direct.618a" + ], + "featureCatalog": { + "contentSha256": "8671f7883c2e5a24474a546ef1517407cd9334258e1a7cfe91e292a9af1952f2", + "id": "ecommerce.questlines" + }, + "diagnostic": true, + "ok": true + } +} diff --git a/tools/stack-bench/qualification-evidence/ecommerce-l3-e804c1302/null-targeted.json b/tools/stack-bench/qualification-evidence/ecommerce-l3-e804c1302/null-targeted.json new file mode 100644 index 00000000000..69b6c412f63 --- /dev/null +++ b/tools/stack-bench/qualification-evidence/ecommerce-l3-e804c1302/null-targeted.json @@ -0,0 +1,115 @@ +{ + "artifactSchemaVersion": 2, + "kind": "null_control", + "id": "null-control-2026-09-18T01-36-17-108Z", + "attempt": { + "id": "null-control-2026-09-18T01-36-17-108Z", + "parentId": null + }, + "timestamps": { + "startedAt": "2026-09-18T01:36:17.108Z", + "completedAt": "2026-09-18T01:36:39.145Z" + }, + "identities": { + "engine": { + "id": "stack-bench", + "sha256": "c5f7dfe76190f44d716012e3c2e69f5ebf550f2364a3ddb5c2fc0be908771934" + }, + "recipe": { + "id": "ecommerce.progression-catalog", + "sha256": "53fbb8093b2335837d88c246f04da99858c40b57ce24d17fbd2b6c815abdb62d" + }, + "fixture": null, + "calibration": { + "id": "ecommerce.dependency-l3-calibration", + "sha256": "253174720de8d80e884e764e4d8018c0a98e1c54b364b33f7679aa189af8d1bd" + }, + "experiment": null, + "agentAdapter": null, + "stackAdapter": null, + "packs": [] + }, + "payload": { + "durationMs": 22037, + "runner": { + "schemaVersion": 1, + "mode": "appliance", + "platform": "linux", + "architecture": "x64", + "hostname": "docker-desktop", + "dockerEngineVersion": "29.6.2", + "dockerOs": "linux", + "dockerArchitecture": "x86_64", + "kernelVersion": "6.6.87.2-microsoft-standard-WSL2", + "cpuCount": 32, + "memoryBytes": 49232842752, + "containersRunning": 9, + "packageRegistry": "http://127.0.0.1:4873/" + }, + "qualificationScope": { + "checksSha256": "b9d7acf0749c3310b680e9376cc4e931cf59382da420a64a4c5e2bf320e89b88", + "executableSha256": "b5a0becb3c1791c4ec00f0a543a3273cd57cf73b69451e981ef8a2092f5bddf7", + "kind": "null", + "mutationSha256": null, + "recipe": { + "contentSha256": "53fbb8093b2335837d88c246f04da99858c40b57ce24d17fbd2b6c815abdb62d", + "id": "ecommerce.progression-catalog" + }, + "schemaVersion": 3, + "stack": null, + "sha256": "ddef8792f386721bcf2bbe836531d5fff8d8539d6835dda004b8733cdb7cc397" + }, + "tracks": [ + "ecommerce" + ], + "ok": true, + "summary": { + "criteria": 1, + "points": 2, + "expectedFailures": { + "criteria": 1, + "points": 2 + }, + "expectedFailureStages": { + "setup": { + "criteria": 1, + "points": 2 + }, + "assertion": { + "criteria": 0, + "points": 0 + } + }, + "vacuousPasses": { + "criteria": 0, + "points": 0 + }, + "oracleGaps": { + "criteria": 0, + "points": 0 + }, + "unscored": { + "criteria": 0, + "passed": 0, + "failed": 0, + "inconclusive": 0 + } + }, + "criteria": [ + { + "track": "ecommerce", + "level": 3, + "suite": "selected-source-093", + "scenario": "scenarios/progression-review-access.json", + "feature": 618, + "featureName": "Review access", + "criterion": "618a", + "points": 2, + "status": "expected_fail", + "evidenceStatus": "blocked", + "failureStage": "setup", + "detail": "Blocked by a failed prerequisite: none of the signup-username, signup-toggle, signin-toggle controls became visible in time" + } + ] + } +} diff --git a/tools/stack-bench/qualification-evidence/ecommerce-l3-e804c1302/postgres-targeted.json b/tools/stack-bench/qualification-evidence/ecommerce-l3-e804c1302/postgres-targeted.json new file mode 100644 index 00000000000..2a413ce0178 --- /dev/null +++ b/tools/stack-bench/qualification-evidence/ecommerce-l3-e804c1302/postgres-targeted.json @@ -0,0 +1,136 @@ +{ + "artifactSchemaVersion": 2, + "kind": "reference_qualification", + "id": "reference-live-postgres-20260918002256-31", + "attempt": { + "id": "reference-live-postgres-20260918002256-31", + "parentId": null + }, + "timestamps": { + "startedAt": "2026-09-18T00:22:56.721Z", + "completedAt": "2026-09-18T00:24:37.025Z" + }, + "identities": { + "engine": { + "id": "stack-bench", + "sha256": "581451119c180f50fd478aa2c17e1fa766fd38e7648e01d8a354334df1b606d3" + }, + "recipe": { + "id": "ecommerce.progression-catalog", + "sha256": "53fbb8093b2335837d88c246f04da99858c40b57ce24d17fbd2b6c815abdb62d" + }, + "fixture": { + "id": "ecommerce-reference-postgres", + "sha256": "f3906fa01050f00a0ed76c69c256a6b0013bbf72eb72c03aa92d79e47b71c2b8" + }, + "calibration": { + "id": "ecommerce.dependency-l3-calibration", + "sha256": "253174720de8d80e884e764e4d8018c0a98e1c54b364b33f7679aa189af8d1bd" + }, + "experiment": null, + "agentAdapter": null, + "stackAdapter": { + "id": "postgres", + "sha256": null + }, + "packs": [] + }, + "payload": { + "fixture": "ecommerce-reference-postgres", + "fixtureSha256": "f3906fa01050f00a0ed76c69c256a6b0013bbf72eb72c03aa92d79e47b71c2b8", + "requiredRepetitions": 1, + "isolation": "docker", + "runner": { + "schemaVersion": 1, + "mode": "appliance", + "platform": "linux", + "architecture": "x64", + "hostname": "docker-desktop", + "dockerEngineVersion": "29.6.2", + "dockerOs": "linux", + "dockerArchitecture": "x86_64", + "kernelVersion": "6.6.87.2-microsoft-standard-WSL2", + "cpuCount": 32, + "memoryBytes": 49232842752, + "containersRunning": 11, + "packageRegistry": "http://127.0.0.1:4873/" + }, + "qualificationScope": { + "checksSha256": "b9d7acf0749c3310b680e9376cc4e931cf59382da420a64a4c5e2bf320e89b88", + "executableSha256": "53b1dcbe4d602e82f17999dc7e49fad71920e5af156e338e3755119e803477dd", + "kind": "mutation", + "mutationSha256": "01083fb8903afe2390d7e2842f4a3877974296032fc79e06d40eee9212cf8beb", + "recipe": { + "contentSha256": "53fbb8093b2335837d88c246f04da99858c40b57ce24d17fbd2b6c815abdb62d", + "id": "ecommerce.progression-catalog" + }, + "schemaVersion": 3, + "stack": { + "id": "postgres", + "reference": { + "id": "ecommerce-reference-postgres", + "sourceSha256": "f3906fa01050f00a0ed76c69c256a6b0013bbf72eb72c03aa92d79e47b71c2b8" + }, + "version": "1.6.0" + }, + "sha256": "e020cbeac0b10f444a73ad15e2911f6c8f692aefb17eccda1d7022143ad46af3" + }, + "mutationControl": true, + "runs": [ + { + "repetition": 1, + "output": "postgres-targeted.runs/r1", + "durationMs": 100100, + "processError": null, + "harnessSha256Before": "8cf33debdb3c7f4797c0b324facba96dd68ca68736c60170d61f7b76f892b9e4", + "harnessSha256After": "8cf33debdb3c7f4797c0b324facba96dd68ca68736c60170d61f7b76f892b9e4", + "ok": true, + "failures": [], + "runId": "ecommerce-postgres-run0-20260918002257-2eb5c097", + "score": "2/2", + "imageId": "sha256:32ff9a9e519ba9d1af2fe72f24622caa8ca7a9f2baf2338c6b1e0435e6ac5455", + "criteria": 1, + "zeroPointCriteria": 0, + "fingerprint": "f1da4e8dbf9629a97b00bb384d6cc95f9a0005fccc9fde991cd1f69b79f8de8d", + "outcome": "passed", + "packRuntime": { + "schemaVersion": 1, + "metric": "pack-check-wall-clock-sum-v1", + "packs": [ + { + "id": "ecommerce.progression.review-access-specifications", + "checkCount": 1, + "setupRuntimeMs": 704, + "criterionRuntimeMs": 6792, + "measuredRuntimeMs": 7496, + "budget": { + "status": "bounded", + "maxRuntimeMs": 82000 + }, + "exceeded": false + } + ] + }, + "mutations": { + "caught": 4, + "completed": 4, + "total": 4, + "remaining": 0 + } + } + ], + "stable": true, + "sameImage": true, + "sameHarness": true, + "harnessSha256": "8cf33debdb3c7f4797c0b324facba96dd68ca68736c60170d61f7b76f892b9e4", + "qualifiedCheckKeys": [ + "ecommerce.progression.review-access-specifications.review-eligibility-direct.618a" + ], + "featureCatalog": { + "contentSha256": "8671f7883c2e5a24474a546ef1517407cd9334258e1a7cfe91e292a9af1952f2", + "id": "ecommerce.questlines" + }, + "diagnostic": true, + "ok": true + } +} diff --git a/tools/stack-bench/qualification-evidence/ecommerce-l3-e804c1302/previous-inputs.json b/tools/stack-bench/qualification-evidence/ecommerce-l3-e804c1302/previous-inputs.json new file mode 100644 index 00000000000..c0096720ad7 --- /dev/null +++ b/tools/stack-bench/qualification-evidence/ecommerce-l3-e804c1302/previous-inputs.json @@ -0,0 +1 @@ +{"documents":{"release":{"capabilities":["backend-lifecycle","browser","concurrent-actors","database-observation","database-read","direct-database-write","direct-server-call","process-crash","request-replay"],"checkCatalog":[{"category":"feature","checkGroupId":"accounts","criterionId":"1a","description":"a visitor can create an account and is signed in as it","executionId":"selected-source-001","featureId":1,"packId":"ecommerce.feature.accounts","points":1,"role":"feature","source":"scenarios/01-account-create.json","stableKey":"ecommerce.feature.accounts.accounts.1a"},{"category":"production","checkGroupId":"accounts","criterionId":"1b","description":"a taken username is refused and does not sign the visitor in as the existing account","executionId":"selected-source-002","featureId":1,"packId":"ecommerce.feature.accounts","points":1,"role":"feature","source":"scenarios/01-account-duplicate.json","stableKey":"ecommerce.feature.accounts.accounts.1b"},{"category":"production","checkGroupId":"accounts","criterionId":"1c","description":"a wrong password is refused","executionId":"selected-source-003","featureId":1,"packId":"ecommerce.feature.accounts","points":1,"role":"feature","source":"scenarios/01-account-password.json","stableKey":"ecommerce.feature.accounts.accounts.1c"},{"category":"production","checkGroupId":"session-reload","criterionId":"1e","description":"the session survives a reload","executionId":"selected-source-004","featureId":1,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.state-durability","points":1,"requiresFeatures":["ecommerce.feature.accounts"],"role":"guarantee","source":"scenarios/01-account-reload.json","stableKey":"ecommerce.spec.state-durability.session-reload.1e"},{"category":"feature","checkGroupId":"accounts","criterionId":"1d","description":"signing out and back in returns the same account","executionId":"selected-source-005","featureId":1,"packId":"ecommerce.feature.accounts","points":1,"role":"feature","source":"scenarios/01-account-signout.json","stableKey":"ecommerce.feature.accounts.accounts.1d"},{"category":"feature","checkGroupId":"admin-write","criterionId":"103a","description":"an administrator can restock a warehouse","executionId":"selected-source-006","featureId":103,"packId":"ecommerce.feature.warehouse-admin","points":1,"role":"feature","source":"scenarios/01-admin-write-staff.json","stableKey":"ecommerce.feature.warehouse-admin.admin-write.103a"},{"category":"production","checkGroupId":"warehouse-write-boundary","criterionId":"103b","description":"the server refuses a warehouse write from staff","executionId":"selected-source-006","featureId":103,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"requiresFeatures":["ecommerce.feature.warehouse-admin"],"role":"guarantee","source":"scenarios/01-admin-write-staff.json","stableKey":"ecommerce.spec.access-control.warehouse-write-boundary.103b"},{"category":"production","checkGroupId":"purchase-stock","criterionId":"3b","description":"buying reduces the stock every other client sees, without a reload","executionId":"selected-source-007","featureId":3,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.live-state","points":2,"requiresFeatures":["ecommerce.feature.catalog-items","ecommerce.feature.purchasing"],"role":"guarantee","source":"scenarios/01-buying.json","stableKey":"ecommerce.spec.live-state.purchase-stock.3b"},{"category":"production","checkGroupId":"cart-boundary","criterionId":"109a","description":"the same cart action run by another customer changes only that customer's cart","executionId":"selected-source-008","featureId":109,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"requiresFeatures":["ecommerce.feature.cart"],"role":"guarantee","source":"scenarios/01-cart-boundary.json","stableKey":"ecommerce.spec.access-control.cart-boundary.109a"},{"category":"production","checkGroupId":"cart-boundary","criterionId":"109b","description":"a negative quantity is refused and leaves the cart unchanged","executionId":"selected-source-008","featureId":109,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":1,"requiresFeatures":["ecommerce.feature.cart"],"role":"guarantee","source":"scenarios/01-cart-boundary.json","stableKey":"ecommerce.spec.access-control.cart-boundary.109b"},{"category":"production","checkGroupId":"cart-reload","criterionId":"4b","description":"the cart survives a reload","executionId":"selected-source-009","featureId":4,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.state-durability","points":1,"requiresFeatures":["ecommerce.feature.cart"],"role":"guarantee","source":"scenarios/01-cart.json","stableKey":"ecommerce.spec.state-durability.cart-reload.4b"},{"category":"production","checkGroupId":"shared-cart","criterionId":"4c","description":"the same account signed in elsewhere sees one cart, live","executionId":"selected-source-009","featureId":4,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.live-state","points":2,"requiresFeatures":["ecommerce.feature.cart"],"role":"guarantee","source":"scenarios/01-cart.json","stableKey":"ecommerce.spec.live-state.shared-cart.4c"},{"category":"feature","checkGroupId":"catalog-ranking","criterionId":"2b","description":"the storefront shows the exact alphabetical top ten before any purchase","executionId":"selected-source-010","featureId":2,"packId":"ecommerce.feature.catalog-discovery","points":1,"role":"feature","source":"scenarios/01-catalog-ranking.json","stableKey":"ecommerce.feature.catalog.catalog-ranking.2b","stablePackId":"ecommerce.feature.catalog"},{"category":"feature","checkGroupId":"catalog-search","criterionId":"2d","description":"case-insensitive partial search finds an item outside the storefront top ten","executionId":"selected-source-011","featureId":2,"packId":"ecommerce.feature.catalog-discovery","points":1,"role":"feature","source":"scenarios/01-catalog-search.json","stableKey":"ecommerce.feature.catalog.catalog-search.2d","stablePackId":"ecommerce.feature.catalog"},{"category":"feature","checkGroupId":"catalog-values","criterionId":"2a","description":"a signed-out visitor sees the seeded item name, price, and total stock","executionId":"selected-source-012","featureId":2,"packId":"ecommerce.feature.catalog-items","points":1,"role":"feature","source":"scenarios/01-catalog-values.json","stableKey":"ecommerce.feature.catalog.catalog-values.2a","stablePackId":"ecommerce.feature.catalog"},{"category":"production","checkGroupId":"ranking","criterionId":"2c","description":"a purchase moves the bought item to the front of the ranking, live","executionId":"selected-source-013","featureId":2,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.live-state","points":1,"requiresFeatures":["ecommerce.feature.catalog-items","ecommerce.feature.purchasing"],"role":"guarantee","source":"scenarios/01-core.json","stableKey":"ecommerce.spec.live-state.ranking.2c"},{"category":"production","checkGroupId":"duplicate-checkout","criterionId":"203a","description":"the same item added from two tabs at once becomes one line of two","executionId":"selected-source-014","featureId":203,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.concurrency-safety","points":1,"requiresFeatures":["ecommerce.feature.checkout"],"role":"guarantee","source":"scenarios/01-duplicate-checkout.json","stableKey":"ecommerce.spec.concurrency-safety.duplicate-checkout.203a"},{"category":"production","checkGroupId":"duplicate-checkout","criterionId":"203b","description":"checking the same cart out twice at once produces one order","executionId":"selected-source-014","featureId":203,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.concurrency-safety","points":1,"requiresFeatures":["ecommerce.feature.checkout"],"role":"guarantee","source":"scenarios/01-duplicate-checkout.json","stableKey":"ecommerce.spec.concurrency-safety.duplicate-checkout.203b"},{"category":"production","checkGroupId":"external-stock","criterionId":"901a","description":"a direct database write sets Desk Lamp's East stock to 5, and the already-open storefront updates from 100 to 50 without a reload or page action","executionId":"selected-source-015","featureId":901,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.external-data-sync","points":1,"requiresFeatures":["ecommerce.feature.warehouse-admin"],"role":"guarantee","source":"scenarios/01-external-live-sync.json","stableKey":"ecommerce.spec.external-data-sync.external-stock.901a"},{"category":"production","checkGroupId":"external-stock","criterionId":"901d","description":"while the storefront is offline, a direct database write sets Desk Lamp's East stock to 7; after reconnecting, the same page catches up from 100 to the authoritative total of 52","executionId":"selected-source-016","featureId":901,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.external-data-sync","points":1,"requiresFeatures":["ecommerce.feature.warehouse-admin"],"role":"guarantee","source":"scenarios/01-external-reconnect-sync.json","stableKey":"ecommerce.spec.external-data-sync.external-stock.901d"},{"checkGroupId":"external-stock","criterionId":"901b","description":"after a direct database write sets Desk Lamp's East stock to 5, a reload reads the persisted total of 50","executionId":"selected-source-017","featureId":901,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.external-data-sync","points":0,"requiresFeatures":["ecommerce.feature.warehouse-admin"],"role":"guarantee","source":"scenarios/01-external-reload-sync.json","stableKey":"ecommerce.spec.external-data-sync.external-stock.901b"},{"category":"production","checkGroupId":"external-stock","criterionId":"901c","description":"a stock correction lands while the app server is stopped, and the already-open storefront shows the authoritative total of 65 after the server returns without a reload","executionId":"selected-source-018","featureId":901,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.external-data-sync","points":1,"requiresFeatures":["ecommerce.feature.warehouse-admin"],"role":"guarantee","source":"scenarios/01-external-server-restart-sync.json","stableKey":"ecommerce.spec.external-data-sync.external-stock.901c"},{"category":"production","checkGroupId":"last-unit","criterionId":"201a","description":"after six customers try to buy the last three units, each warehouse stores zero stock and all observed clients show zero stock","executionId":"selected-source-019","featureId":201,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.concurrency-safety","points":1,"requiresFeatures":["ecommerce.feature.catalog-items","ecommerce.feature.purchasing","ecommerce.feature.warehouse-admin"],"role":"guarantee","source":"scenarios/01-last-unit.json","stableKey":"ecommerce.spec.concurrency-safety.last-unit.201a"},{"category":"production","checkGroupId":"last-unit","criterionId":"201c","description":"revenue increases by exactly three sales, not six","executionId":"selected-source-019","featureId":201,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.concurrency-safety","points":1,"requiresFeatures":["ecommerce.feature.catalog-items","ecommerce.feature.purchasing","ecommerce.feature.warehouse-admin"],"role":"guarantee","source":"scenarios/01-last-unit.json","stableKey":"ecommerce.spec.concurrency-safety.last-unit.201c"},{"category":"production","checkGroupId":"last-unit","criterionId":"201b","description":"the last three units create complete orders for the successful buyers, and all four affordable purchases succeed when stock is sufficient","executionId":"selected-source-019","featureId":201,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.concurrency-safety","points":1,"requiresFeatures":["ecommerce.feature.catalog-items","ecommerce.feature.purchasing","ecommerce.feature.warehouse-admin"],"role":"guarantee","source":"scenarios/01-last-unit.json","stableKey":"ecommerce.spec.concurrency-safety.last-unit.201b"},{"category":"production","checkGroupId":"order-ownership","criterionId":"106a","description":"a working order history contains the customer's own order and not another customer's order","executionId":"selected-source-020","featureId":106,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":1,"requiresFeatures":["ecommerce.feature.purchasing"],"role":"guarantee","source":"scenarios/01-order-ownership.json","stableKey":"ecommerce.spec.access-control.order-ownership.106a"},{"category":"production","checkGroupId":"purchase-attribution","criterionId":"102a","description":"a direct purchase is attributed to the authenticated caller, not another account","executionId":"selected-source-021","featureId":102,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"requiresFeatures":["ecommerce.feature.purchasing"],"role":"guarantee","source":"scenarios/01-purchase-attribution.json","stableKey":"ecommerce.spec.access-control.purchase-attribution.102a"},{"category":"production","checkGroupId":"purchase-session","criterionId":"101a","description":"a valid direct purchase works for the buyer but is refused without a session","executionId":"selected-source-022","featureId":101,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"requiresFeatures":["ecommerce.feature.purchasing"],"role":"guarantee","source":"scenarios/01-purchase-session.json","stableKey":"ecommerce.spec.access-control.purchase-session.101a"},{"category":"feature","checkGroupId":"restock-race","criterionId":"202-control","description":"an uncontended restock of five is stored by the server and shows on the storefront","executionId":"selected-source-023","featureId":202,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.concurrency-safety","points":0,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.warehouse-admin"],"role":"guarantee","source":"scenarios/01-restock-race.json","stableKey":"ecommerce.spec.concurrency-safety.restock-race.202-control"},{"category":"production","checkGroupId":"restock-race","criterionId":"202a","description":"restocking during purchases preserves stock, complete buyer orders and their warehouse allocations","executionId":"selected-source-023","featureId":202,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.concurrency-safety","points":1,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.warehouse-admin"],"role":"guarantee","source":"scenarios/01-restock-race.json","stableKey":"ecommerce.spec.concurrency-safety.restock-race.202a"},{"category":"production","checkGroupId":"review-eligibility","criterionId":"108a","description":"someone who never bought the item cannot review it","executionId":"selected-source-024","featureId":108,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.reviews"],"role":"guarantee","source":"scenarios/01-review-eligibility.json","stableKey":"ecommerce.spec.access-control.review-eligibility.108a"},{"category":"production","checkGroupId":"review-eligibility","criterionId":"108b","description":"buying the item earns the right to review it","executionId":"selected-source-024","featureId":108,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":1,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.reviews"],"role":"guarantee","source":"scenarios/01-review-eligibility.json","stableKey":"ecommerce.spec.access-control.review-eligibility.108b"},{"category":"production","checkGroupId":"rating","criterionId":"6c","description":"the average rating reflects both reviewers and updates live","executionId":"selected-source-025","featureId":6,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.live-state","points":1,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.reviews"],"role":"guarantee","source":"scenarios/01-review-rating-live.json","stableKey":"ecommerce.spec.live-state.rating.6c"},{"category":"production","checkGroupId":"unique-review","criterionId":"6b","description":"a later review submission does not create a duplicate for the same customer and item","executionId":"selected-source-026","featureId":6,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.transactional-integrity","points":1,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.reviews"],"role":"guarantee","source":"scenarios/01-review-uniqueness.json","stableKey":"ecommerce.spec.transactional-integrity.unique-review.6b"},{"category":"feature","checkGroupId":"reviews","criterionId":"6a","description":"a customer can review an item and everyone sees it, signed out included","executionId":"selected-source-027","featureId":6,"packId":"ecommerce.feature.reviews","points":2,"role":"feature","source":"scenarios/01-review-visibility.json","stableKey":"ecommerce.feature.reviews.reviews.6a"},{"category":"production","checkGroupId":"server-price","criterionId":"104a","description":"direct purchases of two differently priced items persist exactly one correctly priced order each","executionId":"selected-source-028","featureId":104,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.transactional-integrity","points":2,"requiresFeatures":["ecommerce.feature.purchasing"],"role":"guarantee","source":"scenarios/01-server-price.json","stableKey":"ecommerce.spec.transactional-integrity.server-price.104a"},{"category":"production","checkGroupId":"warehouse-area-boundary","criterionId":"7a","description":"the administrator area stays unavailable to other staff","executionId":"selected-source-029","featureId":7,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":1,"requiresFeatures":["ecommerce.feature.warehouse-admin"],"role":"guarantee","source":"scenarios/01-warehouse-admin-staff.json","stableKey":"ecommerce.spec.access-control.warehouse-area-boundary.7a"},{"category":"feature","checkGroupId":"warehouse-view","criterionId":"7b","description":"admin lists every item, every warehouse, and what each warehouse holds","executionId":"selected-source-029","featureId":7,"packId":"ecommerce.feature.warehouse-admin","points":1,"role":"feature","source":"scenarios/01-warehouse-admin-staff.json","stableKey":"ecommerce.feature.warehouse-admin.warehouse-view.7b"},{"category":"production","checkGroupId":"warehouse-stock","criterionId":"7c","description":"the storefront stock is the sum across warehouses, and a restock raises it live","executionId":"selected-source-030","featureId":7,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.live-state","points":2,"requiresFeatures":["ecommerce.feature.catalog-items","ecommerce.feature.warehouse-admin"],"role":"guarantee","source":"scenarios/01-warehouse-stock-live-staff.json","stableKey":"ecommerce.spec.live-state.warehouse-stock.7c"},{"category":"production","checkGroupId":"cancellation-and-return","criterionId":"3d","description":"cancelling a pending order removes it from the fulfilment queue","executionId":"selected-source-031","featureId":3,"observations":["requested","unmentioned"],"packId":"ecommerce.progression.cancellation-queue-specifications","points":1,"requiresFeatures":["ecommerce.l2.order-cancellation-features","ecommerce.progression.fulfilment-queue"],"role":"guarantee","source":"scenarios/02-cancellation-queue.json","stableKey":"ecommerce.returns-pricing.cancellation-and-return.3d","stablePackId":"ecommerce.returns-pricing"},{"category":"production","checkGroupId":"fulfilment-area-boundary","criterionId":"1d","description":"staff and administrators can open fulfilment while customers cannot","executionId":"selected-source-032","featureId":1,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":1,"requiresFeatures":["ecommerce.progression.fulfilment-queue"],"role":"guarantee","source":"scenarios/02-fulfilment-access.json","stableKey":"ecommerce.spec.access-control.fulfilment-area-boundary.1d"},{"category":"production","checkGroupId":"fulfilment-queue","criterionId":"1a","description":"an order placed by a customer appears in the staff queue without a reload","executionId":"selected-source-033","featureId":1,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.live-state","points":2,"requiresFeatures":["ecommerce.progression.fulfilment-queue"],"role":"guarantee","source":"scenarios/02-fulfilment-live.json","stableKey":"ecommerce.spec.live-state.fulfilment-queue.1a"},{"category":"feature","checkGroupId":"fulfilment-queue","criterionId":"1c","description":"shipping removes the order from the queue and marks the customer's order shipped","executionId":"selected-source-034","featureId":1,"packId":"ecommerce.progression.fulfilment-queue","points":2,"requiresFeatures":["ecommerce.feature.purchasing"],"role":"feature","source":"scenarios/02-fulfilment-ship.json","stableKey":"ecommerce.operations-access.fulfilment-queue.1c","stablePackId":"ecommerce.operations-access"},{"category":"production","checkGroupId":"refund-accounting","criterionId":"203a","description":"concurrent cancellation restores original stock and the booked amount once, while revenue returns to its prior value","executionId":"selected-source-035","featureId":203,"observations":["requested","unmentioned"],"packId":"ecommerce.progression.cancellation-accounting-specifications","points":3,"requiresFeatures":["ecommerce.l2.order-cancellation-features"],"role":"guarantee","source":"scenarios/02-invariants.json","stableKey":"ecommerce.returns-pricing.refund-accounting.203a","stablePackId":"ecommerce.returns-pricing"},{"category":"production","checkGroupId":"refund-accounting","criterionId":"203b","description":"a price change does not rewrite revenue already earned","executionId":"selected-source-035","featureId":203,"observations":["requested","unmentioned"],"packId":"ecommerce.progression.price-accounting-specifications","points":2,"requiresFeatures":["ecommerce.l2.price-history-features"],"role":"guarantee","source":"scenarios/02-invariants.json","stableKey":"ecommerce.returns-pricing.refund-accounting.203b","stablePackId":"ecommerce.returns-pricing"},{"category":"production","checkGroupId":"price-history","criterionId":"4b","description":"the new price reaches a signed-out visitor without a reload","executionId":"selected-source-036","featureId":4,"packId":"ecommerce.l2.price-history-features","points":2,"role":"feature","source":"scenarios/02-live-price.json","stableKey":"ecommerce.returns-pricing.price-history.4b","stablePackId":"ecommerce.returns-pricing"},{"category":"feature","checkGroupId":"operational-views","criterionId":"5e","description":"the dashboard lists a current low-stock item","executionId":"selected-source-037","featureId":5,"packId":"ecommerce.l2.inventory-dashboard","points":1,"role":"feature","source":"scenarios/02-low-stock.json","stableKey":"ecommerce.inventory-operations.operational-views.5e","stablePackId":"ecommerce.inventory-operations"},{"category":"production","checkGroupId":"inventory-dashboard","criterionId":"5a","description":"an item falling to ten units or fewer joins the low-stock list, live","executionId":"selected-source-037","featureId":5,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.live-state","points":3,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.l2.inventory-dashboard"],"role":"guarantee","source":"scenarios/02-low-stock.json","stableKey":"ecommerce.spec.live-state.inventory-dashboard.5a"},{"category":"feature","checkGroupId":"operational-views","criterionId":"5d","description":"a signed-out visitor sees a best seller in the recommendations list","executionId":"selected-source-038","featureId":5,"packId":"ecommerce.l2.sales-dashboard","points":1,"role":"feature","source":"scenarios/02-operational-best-sellers.json","stableKey":"ecommerce.inventory-operations.operational-views.5d","stablePackId":"ecommerce.inventory-operations"},{"category":"feature","checkGroupId":"operational-views","criterionId":"5f","description":"the dashboard shows category units and revenue","executionId":"selected-source-039","featureId":5,"packId":"ecommerce.l2.sales-dashboard","points":1,"role":"feature","source":"scenarios/02-operational-category-totals.json","stableKey":"ecommerce.inventory-operations.operational-views.5f","stablePackId":"ecommerce.inventory-operations"},{"category":"production","checkGroupId":"sales-dashboard","criterionId":"5b","description":"a purchase updates that category's units and revenue live","executionId":"selected-source-039","featureId":5,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.live-state","points":3,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.l2.sales-dashboard"],"role":"guarantee","source":"scenarios/02-operational-category-totals.json","stableKey":"ecommerce.spec.live-state.sales-dashboard.5b"},{"category":"feature","checkGroupId":"operational-views","criterionId":"5c","description":"a purchase recommends another item from that category and excludes an item in the cart","executionId":"selected-source-040","featureId":5,"packId":"ecommerce.l2.recommendations","points":2,"role":"feature","source":"scenarios/02-operational-recommendations.json","stableKey":"ecommerce.inventory-operations.operational-views.5c","stablePackId":"ecommerce.inventory-operations"},{"category":"production","checkGroupId":"cancellation-and-return","criterionId":"3a","description":"cancelling a pending order restores its stock and revenue","executionId":"selected-source-041","featureId":3,"packId":"ecommerce.l2.order-cancellation-features","points":2,"role":"feature","source":"scenarios/02-order-cancellation-core.json","stableKey":"ecommerce.returns-pricing.cancellation-and-return.3a","stablePackId":"ecommerce.returns-pricing"},{"category":"feature","checkGroupId":"cancellation-and-return","criterionId":"3b","description":"a cancelled order is shown as cancelled in the customer's history","executionId":"selected-source-042","featureId":3,"packId":"ecommerce.l2.order-cancellation-features","points":1,"role":"feature","source":"scenarios/02-order-cancellation-history.json","stableKey":"ecommerce.returns-pricing.cancellation-and-return.3b","stablePackId":"ecommerce.returns-pricing"},{"category":"production","checkGroupId":"price-history","criterionId":"4a","description":"a price change updates the live catalog but leaves the customer's exact paid price unchanged","executionId":"selected-source-043","featureId":4,"observations":["requested","unmentioned"],"packId":"ecommerce.progression.price-history-specifications","points":3,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.l2.price-history-features"],"role":"guarantee","source":"scenarios/02-paid-price-history.json","stableKey":"ecommerce.returns-pricing.price-history.4a","stablePackId":"ecommerce.returns-pricing"},{"category":"feature","checkGroupId":"fulfilment-queue","criterionId":"1b","description":"the queue names the warehouse the order will ship from","executionId":"selected-source-044","featureId":1,"packId":"ecommerce.progression.fulfilment-queue","points":1,"role":"feature","source":"scenarios/02-queue-warehouse.json","stableKey":"ecommerce.operations-access.fulfilment-queue.1b","stablePackId":"ecommerce.operations-access"},{"category":"production","checkGroupId":"stock-conservation","criterionId":"202b","description":"a sale and its cancellation leave the shelf exactly as they found it","executionId":"selected-source-045","featureId":202,"observations":["requested","unmentioned"],"packId":"ecommerce.progression.inventory-conservation-specifications","points":2,"requiresFeatures":["ecommerce.l2.order-cancellation-features"],"role":"guarantee","source":"scenarios/02-self-contained.json","stableKey":"ecommerce.inventory-operations.stock-conservation.202b","stablePackId":"ecommerce.inventory-operations"},{"category":"production","checkGroupId":"stock-conservation","criterionId":"202c","description":"a fresh client sees the restored total after a sale is cancelled","executionId":"selected-source-045","featureId":202,"observations":["requested","unmentioned"],"packId":"ecommerce.progression.inventory-conservation-specifications","points":1,"requiresFeatures":["ecommerce.l2.order-cancellation-features"],"role":"guarantee","source":"scenarios/02-self-contained.json","stableKey":"ecommerce.inventory-operations.stock-conservation.202c","stablePackId":"ecommerce.inventory-operations"},{"category":"production","checkGroupId":"operator-authorization","criterionId":"201c","description":"the server refuses a customer's direct attempt to ship their own pending order","executionId":"selected-source-046","featureId":201,"observations":["requested","unmentioned"],"packId":"ecommerce.progression.operations-access-specifications","points":2,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.progression.fulfilment-queue"],"role":"guarantee","source":"scenarios/02-server-actions.json","stableKey":"ecommerce.operations-access.operator-authorization.201c","stablePackId":"ecommerce.operations-access"},{"category":"production","checkGroupId":"stock-conservation","criterionId":"202d","description":"a direct transfer racing a direct purchase leaves the exact starting total minus the sold unit","executionId":"selected-source-046","featureId":202,"observations":["requested","unmentioned"],"packId":"ecommerce.progression.inventory-conservation-specifications","points":2,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.l2.stock-transfers-features"],"role":"guarantee","source":"scenarios/02-server-actions.json","stableKey":"ecommerce.inventory-operations.stock-conservation.202d","stablePackId":"ecommerce.inventory-operations"},{"category":"production","checkGroupId":"order-owner","criterionId":"204a","description":"the server refuses one customer trying to cancel another customer's still-pending order","executionId":"selected-source-046","featureId":204,"observations":["requested","unmentioned"],"packId":"ecommerce.progression.operations-access-specifications","points":2,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.l2.order-cancellation-features"],"role":"guarantee","source":"scenarios/02-server-actions.json","stableKey":"ecommerce.operations-access.order-owner.204a","stablePackId":"ecommerce.operations-access"},{"category":"production","checkGroupId":"warehouse-transfer","criterionId":"2a","description":"a transfer decreases the source, increases the destination, and preserves the item's exact total","executionId":"selected-source-047","featureId":2,"packId":"ecommerce.l2.stock-transfers-features","points":3,"role":"feature","source":"scenarios/02-strengthened.json","stableKey":"ecommerce.inventory-operations.warehouse-transfer.2a","stablePackId":"ecommerce.inventory-operations"},{"category":"production","checkGroupId":"operator-authorization","criterionId":"201a","description":"the server refuses a customer's direct transfer and neither warehouse nor the item total changes","executionId":"selected-source-047","featureId":201,"observations":["requested","unmentioned"],"packId":"ecommerce.progression.operations-access-specifications","points":2,"requiresFeatures":["ecommerce.l2.stock-transfers-features"],"role":"guarantee","source":"scenarios/02-strengthened.json","stableKey":"ecommerce.operations-access.operator-authorization.201a","stablePackId":"ecommerce.operations-access"},{"category":"production","checkGroupId":"operator-authorization","criterionId":"201b","description":"the server refuses a customer's direct price change and the last accepted price remains exact","executionId":"selected-source-047","featureId":201,"observations":["requested","unmentioned"],"packId":"ecommerce.progression.operations-access-specifications","points":2,"requiresFeatures":["ecommerce.l2.price-history-features"],"role":"guarantee","source":"scenarios/02-strengthened.json","stableKey":"ecommerce.operations-access.operator-authorization.201b","stablePackId":"ecommerce.operations-access"},{"category":"production","checkGroupId":"stock-conservation","criterionId":"202a","description":"a transfer decreases East, increases West, and leaves the item's exact total unchanged","executionId":"selected-source-047","featureId":202,"observations":["requested","unmentioned"],"packId":"ecommerce.progression.inventory-conservation-specifications","points":2,"requiresFeatures":["ecommerce.l2.stock-transfers-features"],"role":"guarantee","source":"scenarios/02-strengthened.json","stableKey":"ecommerce.inventory-operations.stock-conservation.202a","stablePackId":"ecommerce.inventory-operations"},{"category":"production","checkGroupId":"stock-transfer-overdraw","criterionId":"2c","description":"a transfer that would overdraw a warehouse is refused and changes neither warehouse nor the item total","executionId":"selected-source-048","featureId":2,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.transactional-integrity","points":2,"requiresFeatures":["ecommerce.l2.stock-transfers-features"],"role":"guarantee","source":"scenarios/02-transfer-overdraw.json","stableKey":"ecommerce.spec.transactional-integrity.stock-transfer-overdraw.2c"},{"category":"production","checkGroupId":"stock-transfers","criterionId":"2b","description":"both warehouse totals move live and in opposite directions as stock is transferred","executionId":"selected-source-049","featureId":2,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.live-state","points":2,"requiresFeatures":["ecommerce.l2.stock-transfers-features"],"role":"guarantee","source":"scenarios/02-transfer-totals.json","stableKey":"ecommerce.spec.live-state.stock-transfers.2b"},{"category":"production","checkGroupId":"cart-expiration","criterionId":"304a","description":"an inactive cart expires without a browser, releases stock, and returns empty","executionId":"selected-source-050","featureId":304,"packId":"ecommerce.l3.cart-expiration-features","points":4,"role":"feature","source":"scenarios/03-cart-expiration.json","stableKey":"ecommerce.l3.cart-expiration.cart-expiration.304a","stablePackId":"ecommerce.l3.cart-expiration"},{"category":"production","checkGroupId":"scheduled-work-access","criterionId":"317a","description":"the server refuses customer scheduling and cancellation of restocks","executionId":"selected-source-051","featureId":317,"observations":["requested","unmentioned"],"packId":"ecommerce.l3.deferred-access-specifications","points":3,"requiresFeatures":["ecommerce.l3.scheduled-restocks-features"],"role":"guarantee","source":"scenarios/03-deferred-access.json","stableKey":"ecommerce.l3.deferred-access.scheduled-work-access.317a","stablePackId":"ecommerce.l3.deferred-access"},{"category":"production","checkGroupId":"restart-survival","criterionId":"311a","description":"a restock scheduled before restart still applies","executionId":"selected-source-052","featureId":311,"observations":["requested","unmentioned"],"packId":"ecommerce.l3.deferred-durability-specifications","points":4,"requiresFeatures":["ecommerce.l3.scheduled-restocks-features"],"role":"guarantee","source":"scenarios/03-deferred-durability.json","stableKey":"ecommerce.l3.deferred-durability.restart-survival.311a","stablePackId":"ecommerce.l3.deferred-durability"},{"category":"production","checkGroupId":"restart-survival","criterionId":"314a","description":"a reservation pending before restart still expires and returns stock","executionId":"selected-source-052","featureId":314,"observations":["requested","unmentioned"],"packId":"ecommerce.l3.deferred-durability-specifications","points":4,"requiresFeatures":["ecommerce.l3.reservations-features"],"role":"guarantee","source":"scenarios/03-deferred-durability.json","stableKey":"ecommerce.l3.deferred-durability.restart-survival.314a","stablePackId":"ecommerce.l3.deferred-durability"},{"category":"production","checkGroupId":"restart-survival","criterionId":"315a","description":"an order shipped before restart still becomes delivered","executionId":"selected-source-052","featureId":315,"observations":["requested","unmentioned"],"packId":"ecommerce.l3.deferred-durability-specifications","points":4,"requiresFeatures":["ecommerce.l3.order-delivery-features"],"role":"guarantee","source":"scenarios/03-deferred-durability.json","stableKey":"ecommerce.l3.deferred-durability.restart-survival.315a","stablePackId":"ecommerce.l3.deferred-durability"},{"category":"production","checkGroupId":"restart-survival","criterionId":"316a","description":"a cart survives restart and expires near its original five-minute deadline","executionId":"selected-source-052","featureId":316,"observations":["requested","unmentioned"],"packId":"ecommerce.l3.deferred-durability-specifications","points":4,"requiresFeatures":["ecommerce.l3.cart-expiration-features"],"role":"guarantee","source":"scenarios/03-deferred-durability.json","stableKey":"ecommerce.l3.deferred-durability.restart-survival.316a","stablePackId":"ecommerce.l3.deferred-durability"},{"category":"production","checkGroupId":"exactly-once","criterionId":"311a","description":"restart cannot replay a completed restock","executionId":"selected-source-053","featureId":311,"observations":["requested","unmentioned"],"packId":"ecommerce.l3.deferred-integrity-specifications","points":3,"requiresFeatures":["ecommerce.l3.scheduled-restocks-features"],"role":"guarantee","source":"scenarios/03-deferred-integrity.json","stableKey":"ecommerce.l3.deferred-integrity.exactly-once.311a","stablePackId":"ecommerce.l3.deferred-integrity"},{"category":"production","checkGroupId":"exactly-once","criterionId":"312a","description":"restart leaves one delivered order record","executionId":"selected-source-053","featureId":312,"observations":["requested","unmentioned"],"packId":"ecommerce.l3.deferred-integrity-specifications","points":3,"requiresFeatures":["ecommerce.l3.order-delivery-features"],"role":"guarantee","source":"scenarios/03-deferred-integrity.json","stableKey":"ecommerce.l3.deferred-integrity.exactly-once.312a","stablePackId":"ecommerce.l3.deferred-integrity"},{"category":"production","checkGroupId":"stock-conservation","criterionId":"313a","description":"expiry returns exactly the unit reserved","executionId":"selected-source-053","featureId":313,"observations":["requested","unmentioned"],"packId":"ecommerce.l3.deferred-integrity-specifications","points":3,"requiresFeatures":["ecommerce.l3.reservations-features"],"role":"guarantee","source":"scenarios/03-deferred-integrity.json","stableKey":"ecommerce.l3.deferred-integrity.stock-conservation.313a","stablePackId":"ecommerce.l3.deferred-integrity"},{"category":"production","checkGroupId":"stock-conservation","criterionId":"314a","description":"checkout does not decrement stock after the reservation already did","executionId":"selected-source-053","featureId":314,"observations":["requested","unmentioned"],"packId":"ecommerce.l3.deferred-integrity-specifications","points":3,"requiresFeatures":["ecommerce.l3.reservations-features"],"role":"guarantee","source":"scenarios/03-deferred-integrity.json","stableKey":"ecommerce.l3.deferred-integrity.stock-conservation.314a","stablePackId":"ecommerce.l3.deferred-integrity"},{"category":"production","checkGroupId":"order-delivery","criterionId":"303a","description":"a shipped order becomes delivered in customer and staff views","executionId":"selected-source-054","featureId":303,"packId":"ecommerce.l3.order-delivery-features","points":3,"role":"feature","source":"scenarios/03-order-delivery.json","stableKey":"ecommerce.l3.order-delivery.order-delivery.303a","stablePackId":"ecommerce.l3.order-delivery"},{"category":"production","checkGroupId":"order-delivery","criterionId":"305a","description":"a cancelled order remains cancelled after the delivery interval","executionId":"selected-source-054","featureId":305,"packId":"ecommerce.l3.order-delivery-features","points":2,"role":"feature","source":"scenarios/03-order-delivery.json","stableKey":"ecommerce.l3.order-delivery.order-delivery.305a","stablePackId":"ecommerce.l3.order-delivery"},{"category":"production","checkGroupId":"reservations","criterionId":"301a","description":"adding an item reserves one unit for every open viewer","executionId":"selected-source-055","featureId":301,"packId":"ecommerce.l3.reservations-features","points":2,"role":"feature","source":"scenarios/03-reservations.json","stableKey":"ecommerce.l3.reservations.reservations.301a","stablePackId":"ecommerce.l3.reservations"},{"category":"interface","checkGroupId":"reservations","criterionId":"305a","description":"the reservation timer decreases","executionId":"selected-source-055","featureId":305,"packId":"ecommerce.l3.reservations-features","points":1,"role":"feature","source":"scenarios/03-reservations.json","stableKey":"ecommerce.l3.reservations.reservations.305a","stablePackId":"ecommerce.l3.reservations"},{"category":"feature","checkGroupId":"reservations","criterionId":"306a","description":"checkout converts the reservation into an order and empties the cart","executionId":"selected-source-055","featureId":306,"packId":"ecommerce.l3.reservations-features","points":2,"role":"feature","source":"scenarios/03-reservations.json","stableKey":"ecommerce.l3.reservations.reservations.306a","stablePackId":"ecommerce.l3.reservations"},{"category":"feature","checkGroupId":"reservations","criterionId":"307a","description":"an expired reservation marks its cart line","executionId":"selected-source-055","featureId":307,"packId":"ecommerce.l3.reservations-features","points":3,"role":"feature","source":"scenarios/03-reservations.json","stableKey":"ecommerce.l3.reservations.reservations.307a","stablePackId":"ecommerce.l3.reservations"},{"category":"feature","checkGroupId":"reservations","criterionId":"308a","description":"raising quantity starts a new reservation window","executionId":"selected-source-055","featureId":308,"packId":"ecommerce.l3.reservations-features","points":2,"role":"feature","source":"scenarios/03-reservations.json","stableKey":"ecommerce.l3.reservations.reservations.308a","stablePackId":"ecommerce.l3.reservations"},{"category":"feature","checkGroupId":"scheduled-restocks","criterionId":"305a","description":"a due restock updates stock and moves to the ledger","executionId":"selected-source-056","featureId":305,"packId":"ecommerce.l3.scheduled-restocks-features","points":3,"role":"feature","source":"scenarios/03-scheduled-restock-apply.json","stableKey":"ecommerce.l3.scheduled-restocks.scheduled-restocks.305a","stablePackId":"ecommerce.l3.scheduled-restocks"},{"category":"production","checkGroupId":"scheduled-restocks","criterionId":"306a","description":"a cancelled restock never applies","executionId":"selected-source-057","featureId":306,"packId":"ecommerce.l3.scheduled-restocks-features","points":2,"role":"feature","source":"scenarios/03-scheduled-restock-cancel.json","stableKey":"ecommerce.l3.scheduled-restocks.scheduled-restocks.306a","stablePackId":"ecommerce.l3.scheduled-restocks"},{"category":"feature","checkGroupId":"scheduled-restocks","criterionId":"302a","description":"a scheduled restock is pending and its remaining time decreases","executionId":"selected-source-058","featureId":302,"packId":"ecommerce.l3.scheduled-restocks-features","points":2,"role":"feature","source":"scenarios/03-scheduled-restocks.json","stableKey":"ecommerce.l3.scheduled-restocks.scheduled-restocks.302a","stablePackId":"ecommerce.l3.scheduled-restocks"},{"category":"production","checkGroupId":"server-time","criterionId":"312a","description":"restart preserves the due time and the work later completes","executionId":"selected-source-059","featureId":312,"observations":["requested","unmentioned"],"packId":"ecommerce.l3.server-time-specifications","points":3,"requiresFeatures":["ecommerce.l3.scheduled-restocks-features"],"role":"guarantee","source":"scenarios/03-server-time.json","stableKey":"ecommerce.l3.server-time.server-time.312a","stablePackId":"ecommerce.l3.server-time"},{"category":"production","checkGroupId":"server-time","criterionId":"313a","description":"a reservation expires while its browser is closed","executionId":"selected-source-059","featureId":313,"observations":["requested","unmentioned"],"packId":"ecommerce.l3.server-time-specifications","points":3,"requiresFeatures":["ecommerce.l3.reservations-features"],"role":"guarantee","source":"scenarios/03-server-time.json","stableKey":"ecommerce.l3.server-time.server-time.313a","stablePackId":"ecommerce.l3.server-time"},{"category":"production","checkGroupId":"account-state-recovery","criterionId":"105b","description":"the same account and cart survive the connection dropping and coming back","executionId":"selected-source-060","featureId":105,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.state-durability","points":1,"requiresFeatures":["ecommerce.feature.accounts","ecommerce.feature.checkout"],"role":"guarantee","source":"scenarios/progression-account-state-reconnect.json","stableKey":"ecommerce.spec.state-durability.account-state-recovery.105b"},{"category":"production","checkGroupId":"account-state-recovery","criterionId":"105a","description":"cart and order history survive reload and backend restart, including a fresh account login","executionId":"selected-source-061","featureId":105,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.state-durability","points":1,"requiresFeatures":["ecommerce.feature.accounts","ecommerce.feature.checkout"],"role":"guarantee","source":"scenarios/progression-account-state-reload.json","stableKey":"ecommerce.spec.state-durability.account-state-recovery.105a"},{"category":"production","checkGroupId":"automatic-reorder-access","criterionId":"502c","description":"a customer cannot see or replay automatic reorder management","executionId":"selected-source-062","featureId":502,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"requiresFeatures":["ecommerce.progression.automatic-reorder"],"role":"guarantee","source":"scenarios/progression-automatic-reorder-access.json","stableKey":"ecommerce.spec.access-control.automatic-reorder-access.502c"},{"category":"production","checkGroupId":"automatic-reorder-deduplication","criterionId":"502b","description":"more sales do not duplicate a pending restock","executionId":"selected-source-063","featureId":502,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.transactional-integrity","points":2,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.progression.automatic-reorder"],"role":"guarantee","source":"scenarios/progression-automatic-reorder-duplicate.json","stableKey":"ecommerce.spec.transactional-integrity.automatic-reorder-deduplication.502b"},{"category":"feature","checkGroupId":"automatic-reorder","criterionId":"502a","description":"crossing the threshold creates one pending restock","executionId":"selected-source-064","featureId":502,"packId":"ecommerce.progression.automatic-reorder","points":3,"requiresFeatures":["ecommerce.feature.purchasing"],"role":"feature","source":"scenarios/progression-automatic-reorder.json","stableKey":"ecommerce.progression.automatic-reorder.automatic-reorder.502a"},{"category":"production","checkGroupId":"books-balance","criterionId":"107a","description":"revenue rises by exactly what was bought","executionId":"selected-source-065","featureId":107,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.transactional-integrity","points":1,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.warehouse-admin"],"role":"guarantee","source":"scenarios/progression-books-balance.json","stableKey":"ecommerce.spec.transactional-integrity.books-balance.107a"},{"category":"production","checkGroupId":"books-balance","criterionId":"107b","description":"what the store sold is what left the warehouses, and a fresh client agrees","executionId":"selected-source-065","featureId":107,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.transactional-integrity","points":1,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.warehouse-admin"],"role":"guarantee","source":"scenarios/progression-books-balance.json","stableKey":"ecommerce.spec.transactional-integrity.books-balance.107b"},{"category":"feature","checkGroupId":"bundle-checkout","criterionId":"741a","description":"adding a bundle reserves its components and checkout records the bundle price once","executionId":"selected-source-066","featureId":741,"packId":"ecommerce.feature.bundle-checkout","points":2,"role":"feature","source":"scenarios/progression-bundle-checkout.json","stableKey":"ecommerce.feature.bundle-checkout.bundle-checkout.741a"},{"category":"production","checkGroupId":"bundle-744","criterionId":"744a","description":"two competing reservations accept exactly one whole bundle without consuming extra components","executionId":"selected-source-066","featureId":744,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.bundle-integrity","points":3,"requiresFeatures":["ecommerce.feature.bundle-checkout"],"role":"guarantee","source":"scenarios/progression-bundle-checkout.json","stableKey":"ecommerce.spec.bundle-integrity.bundle-744.744a"},{"category":"production","checkGroupId":"bundle-745","criterionId":"745a","description":"a missing component refuses the reservation without taking available stock or adding a cart line","executionId":"selected-source-066","featureId":745,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.bundle-integrity","points":3,"requiresFeatures":["ecommerce.feature.bundle-checkout"],"role":"guarantee","source":"scenarios/progression-bundle-checkout.json","stableKey":"ecommerce.spec.bundle-integrity.bundle-745.745a"},{"category":"production","checkGroupId":"bundle-746","criterionId":"746a","description":"an expired reservation releases each component once across a backend restart","executionId":"selected-source-066","featureId":746,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.bundle-integrity","points":3,"requiresFeatures":["ecommerce.feature.bundle-checkout"],"role":"guarantee","source":"scenarios/progression-bundle-checkout.json","stableKey":"ecommerce.spec.bundle-integrity.bundle-746.746a"},{"category":"production","checkGroupId":"bundle-747","criterionId":"747a","description":"two checkout requests consume one reservation and create one paid bundle","executionId":"selected-source-066","featureId":747,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.bundle-integrity","points":3,"requiresFeatures":["ecommerce.feature.bundle-checkout"],"role":"guarantee","source":"scenarios/progression-bundle-checkout.json","stableKey":"ecommerce.spec.bundle-integrity.bundle-747.747a"},{"category":"feature","checkGroupId":"bundle-returns","criterionId":"742a","description":"returning a shipped bundle refunds the paid price and restores original components after its definition changes","executionId":"selected-source-067","featureId":742,"packId":"ecommerce.feature.bundle-returns","points":2,"role":"feature","source":"scenarios/progression-bundle-returns.json","stableKey":"ecommerce.feature.bundle-returns.bundle-returns.742a"},{"category":"production","checkGroupId":"bundle-742","criterionId":"742b","description":"replaying a completed bundle return after restart does not refund or restock it twice","executionId":"selected-source-067","featureId":742,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.bundle-integrity","points":3,"requiresFeatures":["ecommerce.feature.bundle-returns"],"role":"guarantee","source":"scenarios/progression-bundle-returns.json","stableKey":"ecommerce.spec.bundle-integrity.bundle-742.742b"},{"category":"production","checkGroupId":"bundle-748","criterionId":"748a","description":"another customer cannot return a paid bundle by submitting its order ID","executionId":"selected-source-067","featureId":748,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.bundle-integrity","points":3,"requiresFeatures":["ecommerce.feature.bundle-returns"],"role":"guarantee","source":"scenarios/progression-bundle-returns.json","stableKey":"ecommerce.spec.bundle-integrity.bundle-748.748a"},{"category":"feature","checkGroupId":"cart","criterionId":"4a","description":"adding the same item twice raises its quantity instead of adding a second line","executionId":"selected-source-068","featureId":4,"packId":"ecommerce.feature.cart","points":1,"role":"feature","source":"scenarios/progression-cart-checkout.json","stableKey":"ecommerce.feature.cart-checkout.cart.4a","stablePackId":"ecommerce.feature.cart-checkout"},{"category":"feature","checkGroupId":"cart","criterionId":"4d","description":"checkout creates one order, reduces stock, and empties the cart","executionId":"selected-source-068","featureId":4,"packId":"ecommerce.feature.checkout","points":2,"role":"feature","source":"scenarios/progression-cart-checkout.json","stableKey":"ecommerce.feature.cart-checkout.cart.4d","stablePackId":"ecommerce.feature.cart-checkout"},{"category":"feature","checkGroupId":"cart-recovery","criterionId":"503a","description":"restoring an expired cart reserves available items again","executionId":"selected-source-069","featureId":503,"packId":"ecommerce.progression.cart-recovery","points":3,"role":"feature","source":"scenarios/progression-cart-recovery.json","stableKey":"ecommerce.progression.cart-recovery.cart-recovery.503a"},{"category":"feature","checkGroupId":"cart-recovery","criterionId":"503b","description":"a partial restore keeps available items and names each unavailable item","executionId":"selected-source-069","featureId":503,"packId":"ecommerce.progression.cart-recovery","points":3,"role":"feature","source":"scenarios/progression-cart-recovery.json","stableKey":"ecommerce.progression.cart-recovery.cart-recovery.503b"},{"category":"feature","checkGroupId":"catalog-management","criterionId":"622a","description":"a new product reaches the public catalog","executionId":"selected-source-070","featureId":622,"packId":"ecommerce.progression.catalog-management","points":2,"role":"feature","source":"scenarios/progression-catalog-management.json","stableKey":"ecommerce.progression.catalog-management.catalog-management.622a"},{"category":"feature","checkGroupId":"catalog-management","criterionId":"622b","description":"the product exposes its named variants","executionId":"selected-source-070","featureId":622,"packId":"ecommerce.progression.catalog-management","points":2,"role":"feature","source":"scenarios/progression-catalog-management.json","stableKey":"ecommerce.progression.catalog-management.catalog-management.622b"},{"category":"production","checkGroupId":"checkout-crash-integrity","criterionId":"910a","description":"interrupted checkout recovers to the prepared cart or one complete order with the cart cleared after each independent process crash","executionId":"selected-source-071","featureId":910,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.state-durability","points":1,"requiresFeatures":["ecommerce.feature.checkout"],"role":"guarantee","source":"scenarios/progression-checkout-crash.json","stableKey":"ecommerce.spec.state-durability.checkout-crash-integrity.910a"},{"category":"production","checkGroupId":"checkout-crash-durability","criterionId":"910b","description":"acknowledged checkout is not rolled back and earlier orders remain unchanged after each independent process crash","executionId":"selected-source-071","featureId":910,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.state-durability","points":1,"requiresFeatures":["ecommerce.feature.checkout"],"role":"guarantee","source":"scenarios/progression-checkout-crash.json","stableKey":"ecommerce.spec.state-durability.checkout-crash-durability.910b"},{"category":"production","checkGroupId":"payment-records","criterionId":"623a","description":"checkout records the exact paid amount","executionId":"selected-source-072","featureId":623,"packId":"ecommerce.progression.payment-records","points":3,"role":"feature","source":"scenarios/progression-core-business.json","stableKey":"ecommerce.progression.payment-records.payment-records.623a"},{"category":"production","checkGroupId":"payment-deduplication","criterionId":"623b","description":"one checkout has one payment record","executionId":"selected-source-072","featureId":623,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.transactional-integrity","points":2,"requiresFeatures":["ecommerce.progression.payment-records"],"role":"guarantee","source":"scenarios/progression-core-business.json","stableKey":"ecommerce.spec.transactional-integrity.payment-deduplication.623b"},{"category":"feature","checkGroupId":"customer-profile","criterionId":"620c","description":"the owner can save and view a customer profile","executionId":"selected-source-073","featureId":620,"packId":"ecommerce.progression.customer-profile","points":1,"role":"feature","source":"scenarios/progression-customer-profile.json","stableKey":"ecommerce.progression.customer-profile.customer-profile.620c"},{"category":"production","checkGroupId":"customer-profile-reload","criterionId":"620a","description":"the saved profile survives reload and backend restart in a fresh browser","executionId":"selected-source-073","featureId":620,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.state-durability","points":2,"requiresFeatures":["ecommerce.progression.customer-profile"],"role":"guarantee","source":"scenarios/progression-customer-profile.json","stableKey":"ecommerce.spec.state-durability.customer-profile-reload.620a"},{"category":"production","checkGroupId":"customer-profile-privacy","criterionId":"620b","description":"another customer neither sees nor receives the owner's private address","executionId":"selected-source-073","featureId":620,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"requiresFeatures":["ecommerce.progression.customer-profile"],"role":"guarantee","source":"scenarios/progression-customer-profile.json","stableKey":"ecommerce.spec.access-control.customer-profile-privacy.620b"},{"category":"feature","checkGroupId":"delivery-notification-delivery","criterionId":"501a","description":"the order owner receives one delivery notification","executionId":"selected-source-074","featureId":501,"packId":"ecommerce.progression.delivery-notifications","points":3,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.progression.fulfilment-queue"],"role":"feature","source":"scenarios/progression-delivery-notifications.json","stableKey":"ecommerce.progression.delivery-notifications.delivery-notification-delivery.501a"},{"category":"production","checkGroupId":"delivery-notification-privacy","criterionId":"501b","description":"another customer cannot see the delivery notification","executionId":"selected-source-074","featureId":501,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.progression.delivery-notifications","ecommerce.progression.fulfilment-queue"],"role":"guarantee","source":"scenarios/progression-delivery-notifications.json","stableKey":"ecommerce.spec.access-control.delivery-notification-privacy.501b"},{"category":"feature","checkGroupId":"faceted-search","criterionId":"401a","description":"category, price, and availability filters apply together","executionId":"selected-source-075","featureId":401,"packId":"ecommerce.progression.faceted-search","points":3,"role":"feature","source":"scenarios/progression-faceted-filters.json","stableKey":"ecommerce.progression.faceted-search.faceted-search.401a"},{"category":"feature","checkGroupId":"faceted-search","criterionId":"402a","description":"moving between pages returns the same ordered items without duplicates","executionId":"selected-source-076","featureId":402,"packId":"ecommerce.progression.faceted-search","points":3,"role":"feature","source":"scenarios/progression-faceted-pagination.json","stableKey":"ecommerce.progression.faceted-search.faceted-search.402a"},{"category":"production","checkGroupId":"managed-support-privacy","criterionId":"613b","description":"another customer cannot read or reply to the managed case","executionId":"selected-source-077","featureId":613,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":1,"requiresFeatures":["ecommerce.progression.managed-support"],"role":"guarantee","source":"scenarios/progression-managed-support-privacy.json","stableKey":"ecommerce.spec.access-control.managed-support-privacy.613b"},{"category":"feature","checkGroupId":"managed-support","criterionId":"613c","description":"staff can update a support case and the customer can reply","executionId":"selected-source-078","featureId":613,"packId":"ecommerce.progression.managed-support","points":1,"role":"feature","source":"scenarios/progression-managed-support-shared.json","stableKey":"ecommerce.progression.managed-support.managed-support.613c"},{"category":"production","checkGroupId":"managed-support","criterionId":"613a","description":"the customer and staff see the same replies and status live","executionId":"selected-source-078","featureId":613,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.live-state","points":2,"requiresFeatures":["ecommerce.progression.managed-support"],"role":"guarantee","source":"scenarios/progression-managed-support-shared.json","stableKey":"ecommerce.spec.live-state.managed-support.613a"},{"category":"feature","checkGroupId":"notification-preferences","criterionId":"630c","description":"the customer can save a notification choice","executionId":"selected-source-079","featureId":630,"packId":"ecommerce.progression.notification-preferences","points":1,"role":"feature","source":"scenarios/progression-notification-preferences.json","stableKey":"ecommerce.progression.notification-preferences.notification-preferences.630c"},{"category":"production","checkGroupId":"notification-preferences-reload","criterionId":"630a","description":"notification choices survive reload and backend restart in a fresh browser","executionId":"selected-source-079","featureId":630,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.state-durability","points":2,"requiresFeatures":["ecommerce.progression.notification-preferences"],"role":"guarantee","source":"scenarios/progression-notification-preferences.json","stableKey":"ecommerce.spec.state-durability.notification-preferences-reload.630a"},{"category":"production","checkGroupId":"notification-preferences-privacy","criterionId":"630b","description":"the owner's choice does not change another account","executionId":"selected-source-079","featureId":630,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"requiresFeatures":["ecommerce.progression.notification-preferences"],"role":"guarantee","source":"scenarios/progression-notification-preferences.json","stableKey":"ecommerce.spec.access-control.notification-preferences-privacy.630b"},{"category":"production","checkGroupId":"open-list","criterionId":"902a","description":"one customer has the Keyboard's reviews open before another posts one; the already-open view shows that review exactly once","executionId":"selected-source-080","featureId":902,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.live-state","points":1,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.reviews"],"role":"guarantee","source":"scenarios/progression-open-list-live.json","stableKey":"ecommerce.spec.live-state.open-list.902a"},{"category":"interface","checkGroupId":"cancellation-and-return","criterionId":"3e","description":"a pending order does not offer a return button","executionId":"selected-source-081","featureId":331,"packId":"ecommerce.l3.order-returns-features","points":1,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.progression.fulfilment-queue"],"role":"feature","source":"scenarios/progression-order-return-boundary.json","stableKey":"ecommerce.returns-pricing.cancellation-and-return.3e","stablePackId":"ecommerce.returns-pricing"},{"category":"production","checkGroupId":"cancellation-and-return","criterionId":"3f","description":"the server refuses a pending return without changing stock or revenue","executionId":"selected-source-081","featureId":332,"packId":"ecommerce.l3.order-returns-features","points":2,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.progression.fulfilment-queue"],"role":"feature","source":"scenarios/progression-order-return-boundary.json","stableKey":"ecommerce.returns-pricing.cancellation-and-return.3f","stablePackId":"ecommerce.returns-pricing"},{"category":"production","checkGroupId":"cancellation-and-return","criterionId":"3c","description":"returning a shipped item restores stock and revenue and marks the item returned","executionId":"selected-source-082","featureId":330,"packId":"ecommerce.l3.order-returns-features","points":3,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.progression.fulfilment-queue"],"role":"feature","source":"scenarios/progression-order-return-complete.json","stableKey":"ecommerce.returns-pricing.cancellation-and-return.3c","stablePackId":"ecommerce.returns-pricing"},{"category":"production","checkGroupId":"order-support-ownership","criterionId":"614b","description":"another customer cannot attach or inspect the owner's order","executionId":"selected-source-083","featureId":614,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"requiresFeatures":["ecommerce.progression.order-support"],"role":"guarantee","source":"scenarios/progression-order-support-boundary.json","stableKey":"ecommerce.spec.access-control.order-support-ownership.614b"},{"category":"feature","checkGroupId":"order-support-owned","criterionId":"614a","description":"the customer can link their order and staff can inspect it","executionId":"selected-source-084","featureId":614,"packId":"ecommerce.progression.order-support","points":3,"role":"feature","source":"scenarios/progression-order-support-owned.json","stableKey":"ecommerce.progression.order-support.order-support-owned.614a"},{"category":"feature","checkGroupId":"personalized-recommendations","criterionId":"403a","description":"recommendations follow the customer's categories, global sales, and name tie-break","executionId":"selected-source-085","featureId":403,"packId":"ecommerce.progression.personalized-recommendations","points":4,"role":"feature","source":"scenarios/progression-personalized-recommendations.json","stableKey":"ecommerce.progression.personalized-recommendations.personalized-recommendations.403a"},{"category":"production","checkGroupId":"recommendation-profile-isolation","criterionId":"403b","description":"one customer's activity does not replace another customer's recommendations","executionId":"selected-source-085","featureId":403,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"requiresFeatures":["ecommerce.progression.personalized-recommendations"],"role":"guarantee","source":"scenarios/progression-personalized-recommendations.json","stableKey":"ecommerce.spec.access-control.recommendation-profile-isolation.403b"},{"category":"production","checkGroupId":"price-history","criterionId":"4c","description":"a price change updates an open cart and direct checkout persists the new total","executionId":"selected-source-086","featureId":420,"observations":["requested","unmentioned"],"packId":"ecommerce.progression.price-history-specifications","points":3,"requiresFeatures":["ecommerce.feature.checkout","ecommerce.l2.price-history-features"],"role":"guarantee","source":"scenarios/progression-price-cart-checkout.json","stableKey":"ecommerce.returns-pricing.price-history.4c","stablePackId":"ecommerce.returns-pricing"},{"category":"feature","checkGroupId":"product-bundles","criterionId":"740a","description":"a saved bundle shows the exact price and component quantities after reopening the application","executionId":"selected-source-087","featureId":740,"packId":"ecommerce.feature.product-bundles","points":2,"role":"feature","source":"scenarios/progression-product-bundles.json","stableKey":"ecommerce.feature.product-bundles.product-bundles.740a"},{"category":"production","checkGroupId":"bundle-743","criterionId":"743a","description":"a customer cannot replace a staff-created bundle through the application write","executionId":"selected-source-087","featureId":743,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.bundle-integrity","points":3,"requiresFeatures":["ecommerce.feature.product-bundles"],"role":"guarantee","source":"scenarios/progression-product-bundles.json","stableKey":"ecommerce.spec.bundle-integrity.bundle-743.743a"},{"category":"feature","checkGroupId":"promotion-checkout-active","criterionId":"621a","description":"an active promotion changes checkout and is recorded on the order","executionId":"selected-source-088","featureId":621,"packId":"ecommerce.progression.promotion-checkout","points":3,"role":"feature","source":"scenarios/progression-promotion-checkout.json","stableKey":"ecommerce.progression.promotion-checkout.promotion-checkout-active.621a"},{"category":"feature","checkGroupId":"promotion-checkout-expired","criterionId":"621b","description":"an expired promotion is refused","executionId":"selected-source-088","featureId":621,"packId":"ecommerce.progression.promotion-checkout","points":2,"role":"feature","source":"scenarios/progression-promotion-checkout.json","stableKey":"ecommerce.progression.promotion-checkout.promotion-checkout-expired.621b"},{"category":"feature","checkGroupId":"promotion-checkout-exhausted","criterionId":"621c","description":"a fully redeemed promotion is refused","executionId":"selected-source-088","featureId":621,"packId":"ecommerce.progression.promotion-checkout","points":2,"role":"feature","source":"scenarios/progression-promotion-checkout.json","stableKey":"ecommerce.progression.promotion-checkout.promotion-checkout-exhausted.621c"},{"category":"feature","checkGroupId":"promotion-report-redemptions","criterionId":"622a","description":"the promotion report has the exact redemption count","executionId":"selected-source-089","featureId":622,"packId":"ecommerce.progression.promotion-reporting","points":1,"role":"feature","source":"scenarios/progression-promotion-reporting.json","stableKey":"ecommerce.progression.promotion-reporting.promotion-report-redemptions.622a"},{"category":"feature","checkGroupId":"promotion-report-revenue","criterionId":"622b","description":"the promotion report has the exact discounted revenue","executionId":"selected-source-089","featureId":622,"packId":"ecommerce.progression.promotion-reporting","points":2,"role":"feature","source":"scenarios/progression-promotion-reporting.json","stableKey":"ecommerce.progression.promotion-reporting.promotion-report-revenue.622b"},{"category":"feature","checkGroupId":"promotion-rule-values","criterionId":"620a","description":"staff can save every bounded promotion value","executionId":"selected-source-090","featureId":620,"packId":"ecommerce.progression.promotion-rules","points":2,"role":"feature","source":"scenarios/progression-promotion-rules.json","stableKey":"ecommerce.progression.promotion-rules.promotion-rule-values.620a"},{"category":"production","checkGroupId":"promotion-management-boundary","criterionId":"620b","description":"customers cannot open promotion management","executionId":"selected-source-090","featureId":620,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"requiresFeatures":["ecommerce.progression.promotion-rules"],"role":"guarantee","source":"scenarios/progression-promotion-rules.json","stableKey":"ecommerce.spec.access-control.promotion-management-boundary.620b"},{"category":"feature","checkGroupId":"purchase-order","criterionId":"3c","description":"the purchase is recorded in the buyer's order history at the price paid","executionId":"selected-source-091","featureId":3,"packId":"ecommerce.feature.purchasing","points":1,"role":"feature","source":"scenarios/progression-purchasing.json","stableKey":"ecommerce.feature.purchasing.purchase-order.3c"},{"category":"feature","checkGroupId":"recommendation-feedback","criterionId":"504a","description":"dismissing a recommendation removes it from the customer view","executionId":"selected-source-092","featureId":504,"packId":"ecommerce.progression.recommendation-feedback","points":2,"role":"feature","source":"scenarios/progression-recommendation-feedback.json","stableKey":"ecommerce.progression.recommendation-feedback.recommendation-feedback.504a"},{"category":"production","checkGroupId":"recommendation-feedback-privacy","criterionId":"504b","description":"one customer's dismissal does not hide another customer's result","executionId":"selected-source-092","featureId":504,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"requiresFeatures":["ecommerce.progression.recommendation-feedback"],"role":"guarantee","source":"scenarios/progression-recommendation-feedback.json","stableKey":"ecommerce.spec.access-control.recommendation-feedback-privacy.504b"},{"category":"production","checkGroupId":"recommendation-feedback-restart","criterionId":"504c","description":"a dismissed recommendation stays absent after reload and backend restart in a fresh browser","executionId":"selected-source-092","featureId":504,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.state-durability","points":2,"requiresFeatures":["ecommerce.progression.recommendation-feedback"],"role":"guarantee","source":"scenarios/progression-recommendation-feedback.json","stableKey":"ecommerce.spec.state-durability.recommendation-feedback-restart.504c"},{"category":"production","checkGroupId":"review-eligibility-direct","criterionId":"618a","description":"the server refuses a review from a customer who did not buy the item","executionId":"selected-source-093","featureId":618,"observations":["requested","unmentioned"],"packId":"ecommerce.progression.review-access-specifications","points":2,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.reviews"],"role":"guarantee","source":"scenarios/progression-review-access.json","stableKey":"ecommerce.progression.review-access-specifications.review-eligibility-direct.618a"},{"category":"production","checkGroupId":"stored-review-script","criterionId":"9180a","description":"review input is rejected or displayed without executing script in another customer session","executionId":"selected-source-094","featureId":9180,"observations":["unmentioned"],"packId":"ecommerce.progression.review-access-specifications","points":1,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.reviews"],"role":"guarantee","source":"scenarios/progression-review-script.json","stableKey":"ecommerce.progression.review-access-specifications.stored-review-script.9180a"},{"category":"production","checkGroupId":"search-ordering","criterionId":"402b","description":"active filters and text searches remain alphabetical after purchases; clearing them restores purchase ranking","executionId":"selected-source-095","featureId":402,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.search-ordering","points":1,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.progression.faceted-search"],"role":"guarantee","source":"scenarios/progression-search-ordering.json","stableKey":"ecommerce.spec.search-ordering.search-ordering.402b"},{"category":"production","checkGroupId":"shipping-accounting","criterionId":"202e","description":"shipping a purchased order does not deduct stock or add revenue again","executionId":"selected-source-096","featureId":202,"observations":["requested","unmentioned"],"packId":"ecommerce.progression.inventory-conservation-specifications","points":2,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.warehouse-admin","ecommerce.progression.fulfilment-queue"],"role":"guarantee","source":"scenarios/progression-shipping-accounting.json","stableKey":"ecommerce.inventory-operations.shipping-accounting.202e","stablePackId":"ecommerce.inventory-operations"},{"category":"production","checkGroupId":"signed-out-purchase","criterionId":"3a","description":"using the purchase control while signed out does not buy an item","executionId":"selected-source-097","featureId":3,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":1,"requiresFeatures":["ecommerce.feature.purchasing"],"role":"guarantee","source":"scenarios/progression-signed-out-purchase.json","stableKey":"ecommerce.spec.access-control.signed-out-purchase.3a"},{"category":"feature","checkGroupId":"split-tender-refunds-751","criterionId":"751a","description":"Full refund restores each original payment portion","executionId":"selected-source-098","featureId":751,"packId":"ecommerce.feature.split-tender-refunds","points":2,"requiresFeatures":["ecommerce.feature.split-tender-refunds","ecommerce.feature.store-credit","ecommerce.progression.support-refunds"],"role":"feature","source":"scenarios/progression-split-tender-refunds.json","stableKey":"ecommerce.feature.split-tender-refunds.split-tender-refunds-751.751a"},{"category":"production","checkGroupId":"production-756","criterionId":"756a","description":"Concurrent refunds restore the original credit and external amounts once, including after restart","executionId":"selected-source-098","featureId":756,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.split-tender-refunds","points":2,"requiresFeatures":["ecommerce.feature.split-tender-refunds","ecommerce.feature.store-credit","ecommerce.progression.support-refunds"],"role":"guarantee","source":"scenarios/progression-split-tender-refunds.json","stableKey":"ecommerce.spec.split-tender-refunds.production-756.756a"},{"category":"feature","checkGroupId":"staff-access","criterionId":"601a","description":"staff and administrators can sign in and open staff tools","executionId":"selected-source-099","featureId":601,"packId":"ecommerce.progression.staff-access","points":2,"role":"feature","source":"scenarios/progression-staff-access.json","stableKey":"ecommerce.progression.staff-access.staff-access.601a"},{"category":"production","checkGroupId":"staff-area-boundary","criterionId":"601b","description":"customers cannot open staff tools","executionId":"selected-source-099","featureId":601,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"requiresFeatures":["ecommerce.progression.staff-access"],"role":"guarantee","source":"scenarios/progression-staff-access.json","stableKey":"ecommerce.spec.access-control.staff-area-boundary.601b"},{"category":"feature","checkGroupId":"staff-activity","criterionId":"624a","description":"an administrative change records its actor, action, subject, and time","executionId":"selected-source-100","featureId":624,"packId":"ecommerce.progression.staff-activity","points":3,"role":"feature","source":"scenarios/progression-staff-activity.json","stableKey":"ecommerce.progression.staff-activity.staff-activity.624a"},{"category":"production","checkGroupId":"staff-activity-privacy","criterionId":"624b","description":"customers cannot open staff activity history","executionId":"selected-source-100","featureId":624,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"requiresFeatures":["ecommerce.progression.staff-activity"],"role":"guarantee","source":"scenarios/progression-staff-activity.json","stableKey":"ecommerce.spec.access-control.staff-activity-privacy.624b"},{"category":"feature","checkGroupId":"staff-roles","criterionId":"621c","description":"an administrator can assign a staff role","executionId":"selected-source-101","featureId":621,"packId":"ecommerce.progression.staff-roles","points":1,"role":"feature","source":"scenarios/progression-staff-roles.json","stableKey":"ecommerce.progression.staff-roles.staff-roles.621c"},{"category":"production","checkGroupId":"staff-role-reload","criterionId":"621a","description":"an assigned staff role survives reload and backend restart in a fresh browser","executionId":"selected-source-101","featureId":621,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.state-durability","points":2,"requiresFeatures":["ecommerce.progression.staff-roles"],"role":"guarantee","source":"scenarios/progression-staff-roles.json","stableKey":"ecommerce.spec.state-durability.staff-role-reload.621a"},{"category":"production","checkGroupId":"staff-role-boundary","criterionId":"621b","description":"a staff member cannot assign roles through the UI or a replayed request","executionId":"selected-source-101","featureId":621,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"requiresFeatures":["ecommerce.progression.staff-roles"],"role":"guarantee","source":"scenarios/progression-staff-roles.json","stableKey":"ecommerce.spec.access-control.staff-role-boundary.621b"},{"category":"production","checkGroupId":"staff-role-revocation","criterionId":"621d","description":"removing administrator access blocks a previously authorized session without changing the target role","executionId":"selected-source-101","featureId":621,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"requiresFeatures":["ecommerce.progression.staff-roles"],"role":"guarantee","source":"scenarios/progression-staff-roles.json","stableKey":"ecommerce.spec.access-control.staff-role-revocation.621d"},{"category":"feature","checkGroupId":"stock-alert-delivery","criterionId":"631c","description":"restored stock sends the requested alert","executionId":"selected-source-102","featureId":631,"packId":"ecommerce.progression.stock-alerts","points":1,"requiresFeatures":["ecommerce.feature.warehouse-admin"],"role":"feature","source":"scenarios/progression-stock-alert-delivery.json","stableKey":"ecommerce.progression.stock-alerts.stock-alert-delivery.631c"},{"category":"production","checkGroupId":"stock-alert-deduplication","criterionId":"631a","description":"restored stock sends one alert and later restocks do not duplicate it","executionId":"selected-source-103","featureId":631,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.transactional-integrity","points":2,"requiresFeatures":["ecommerce.feature.warehouse-admin","ecommerce.progression.stock-alerts"],"role":"guarantee","source":"scenarios/progression-stock-alerts.json","stableKey":"ecommerce.spec.transactional-integrity.stock-alert-deduplication.631a"},{"category":"production","checkGroupId":"stock-alert-privacy","criterionId":"631b","description":"a customer who did not request the alert cannot see it","executionId":"selected-source-103","featureId":631,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":1,"requiresFeatures":["ecommerce.feature.warehouse-admin","ecommerce.progression.stock-alerts"],"role":"guarantee","source":"scenarios/progression-stock-alerts.json","stableKey":"ecommerce.spec.access-control.stock-alert-privacy.631b"},{"category":"production","checkGroupId":"stock-limit","criterionId":"3d","description":"an item sells out visibly, and a further purchase is refused without changing stock","executionId":"selected-source-104","featureId":3,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.concurrency-safety","points":2,"requiresFeatures":["ecommerce.feature.purchasing"],"role":"guarantee","source":"scenarios/progression-stock-limit.json","stableKey":"ecommerce.spec.concurrency-safety.stock-limit.3d"},{"category":"feature","checkGroupId":"store-credit-750","criterionId":"750a","description":"Credit checkout records both payment portions","executionId":"selected-source-105","featureId":750,"packId":"ecommerce.feature.store-credit","points":2,"role":"feature","source":"scenarios/progression-store-credit.json","stableKey":"ecommerce.feature.store-credit.store-credit-750.750a"},{"category":"production","checkGroupId":"production-752","criterionId":"752a","description":"Repeating a grant reference does not increase the balance twice","executionId":"selected-source-105","featureId":752,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.store-credit","points":2,"requiresFeatures":["ecommerce.feature.store-credit"],"role":"guarantee","source":"scenarios/progression-store-credit.json","stableKey":"ecommerce.spec.store-credit.production-752.752a"},{"category":"production","checkGroupId":"production-753","criterionId":"753a","description":"A customer cannot grant credit","executionId":"selected-source-105","featureId":753,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.store-credit","points":2,"requiresFeatures":["ecommerce.feature.store-credit"],"role":"guarantee","source":"scenarios/progression-store-credit.json","stableKey":"ecommerce.spec.store-credit.production-753.753a"},{"category":"production","checkGroupId":"production-754","criterionId":"754a","description":"Concurrent checkout consumes one cart and one credit allocation","executionId":"selected-source-105","featureId":754,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.store-credit","points":2,"requiresFeatures":["ecommerce.feature.store-credit"],"role":"guarantee","source":"scenarios/progression-store-credit.json","stableKey":"ecommerce.spec.store-credit.production-754.754a"},{"category":"production","checkGroupId":"production-755","criterionId":"755a","description":"Issued credit survives a backend restart","executionId":"selected-source-105","featureId":755,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.store-credit","points":2,"requiresFeatures":["ecommerce.feature.store-credit"],"role":"guarantee","source":"scenarios/progression-store-credit.json","stableKey":"ecommerce.spec.store-credit.production-755.755a"},{"category":"feature","checkGroupId":"subscriptions-760","criterionId":"760a","description":"A subscription creates exactly its requested deliveries and payments","executionId":"selected-source-106","featureId":760,"packId":"ecommerce.feature.subscriptions","points":2,"role":"feature","source":"scenarios/progression-subscriptions.json","stableKey":"ecommerce.feature.subscriptions.subscriptions-760.760a"},{"category":"production","checkGroupId":"production-761","criterionId":"761a","description":"A pending subscription continues after backend restart without duplicate deliveries","executionId":"selected-source-106","featureId":761,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.subscriptions","points":2,"requiresFeatures":["ecommerce.feature.subscriptions"],"role":"guarantee","source":"scenarios/progression-subscriptions.json","stableKey":"ecommerce.spec.subscriptions.production-761.761a"},{"category":"production","checkGroupId":"production-762","criterionId":"762a","description":"Another customer cannot cancel an active subscription","executionId":"selected-source-106","featureId":762,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.subscriptions","points":2,"requiresFeatures":["ecommerce.feature.subscriptions"],"role":"guarantee","source":"scenarios/progression-subscriptions.json","stableKey":"ecommerce.spec.subscriptions.production-762.762a"},{"category":"production","checkGroupId":"production-763","criterionId":"763a","description":"Pause survives a restart and resume completes the remaining deliveries","executionId":"selected-source-106","featureId":763,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.subscriptions","points":2,"requiresFeatures":["ecommerce.feature.subscriptions"],"role":"guarantee","source":"scenarios/progression-subscriptions.json","stableKey":"ecommerce.spec.subscriptions.production-763.763a"},{"category":"feature","checkGroupId":"support-history","criterionId":"612c","description":"the customer can view their support ticket history","executionId":"selected-source-107","featureId":612,"packId":"ecommerce.progression.support-history","points":1,"role":"feature","source":"scenarios/progression-support-history.json","stableKey":"ecommerce.progression.support-history.support-history.612c"},{"category":"production","checkGroupId":"support-history-reload","criterionId":"612a","description":"support history survives reload and backend restart in a fresh browser","executionId":"selected-source-107","featureId":612,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.state-durability","points":2,"requiresFeatures":["ecommerce.progression.support-history"],"role":"guarantee","source":"scenarios/progression-support-history.json","stableKey":"ecommerce.spec.state-durability.support-history-reload.612a"},{"category":"production","checkGroupId":"support-history-privacy","criterionId":"612b","description":"another customer neither sees nor receives the private ticket","executionId":"selected-source-107","featureId":612,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"requiresFeatures":["ecommerce.progression.support-history"],"role":"guarantee","source":"scenarios/progression-support-history.json","stableKey":"ecommerce.spec.access-control.support-history-privacy.612b"},{"category":"production","checkGroupId":"support-history-logout","criterionId":"612d","description":"after logout the same browser storage no longer grants access to private support history","executionId":"selected-source-107","featureId":612,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"requiresFeatures":["ecommerce.progression.support-history"],"role":"guarantee","source":"scenarios/progression-support-history.json","stableKey":"ecommerce.spec.access-control.support-history-logout.612d"},{"category":"feature","checkGroupId":"support-intake","criterionId":"610a","description":"a visitor can submit a support ticket and receives a reference","executionId":"selected-source-108","featureId":610,"packId":"ecommerce.progression.support-intake","points":2,"role":"feature","source":"scenarios/progression-support-intake.json","stableKey":"ecommerce.progression.support-intake.support-intake.610a"},{"category":"production","checkGroupId":"support-refund-access","criterionId":"615c","description":"a customer cannot issue a refund or change its records","executionId":"selected-source-109","featureId":615,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":1,"requiresFeatures":["ecommerce.progression.support-refunds"],"role":"guarantee","source":"scenarios/progression-support-refunds-access.json","stableKey":"ecommerce.spec.access-control.support-refund-access.615c"},{"category":"production","checkGroupId":"support-refund-accounting","criterionId":"615b","description":"the refund equals the paid total, cannot be applied twice, and leaves another order unrefunded","executionId":"selected-source-110","featureId":615,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.transactional-integrity","points":1,"requiresFeatures":["ecommerce.progression.support-refunds"],"role":"guarantee","source":"scenarios/progression-support-refunds-accounting.json","stableKey":"ecommerce.spec.transactional-integrity.support-refund-accounting.615b"},{"category":"feature","checkGroupId":"support-refunds-resolution","criterionId":"615a","description":"an authorized refund resolves the case and updates the order","executionId":"selected-source-111","featureId":615,"packId":"ecommerce.progression.support-refunds","points":2,"role":"feature","source":"scenarios/progression-support-refunds-resolution.json","stableKey":"ecommerce.progression.support-refunds.support-refunds-resolution.615a"},{"category":"production","checkGroupId":"return-refund-interaction","criterionId":"757a","description":"a support refund followed by physical return restores each warehouse once and refunds only the price paid","executionId":"selected-source-112","featureId":757,"packId":"ecommerce.feature.split-tender-refunds","points":2,"requiresFeatures":["ecommerce.l3.order-returns-features","ecommerce.progression.fulfilment-queue","ecommerce.progression.support-refunds"],"role":"feature","source":"scenarios/progression-support-return-interaction.json","stableKey":"ecommerce.feature.split-tender-refunds.return-refund-interaction.757a"},{"category":"production","checkGroupId":"return-refund-interaction","criterionId":"757b","description":"a physical return followed by support refund restores each warehouse once and refunds only the price paid","executionId":"selected-source-112","featureId":757,"packId":"ecommerce.feature.split-tender-refunds","points":2,"requiresFeatures":["ecommerce.l3.order-returns-features","ecommerce.progression.fulfilment-queue","ecommerce.progression.support-refunds"],"role":"feature","source":"scenarios/progression-support-return-interaction.json","stableKey":"ecommerce.feature.split-tender-refunds.return-refund-interaction.757b"},{"category":"feature","checkGroupId":"support-assignment","criterionId":"611a","description":"staff can assign a new ticket","executionId":"selected-source-113","featureId":611,"packId":"ecommerce.progression.support-triage","points":1,"role":"feature","source":"scenarios/progression-support-triage.json","stableKey":"ecommerce.progression.support-triage.support-assignment.611a"},{"category":"feature","checkGroupId":"support-priority","criterionId":"611b","description":"staff can set a ticket priority","executionId":"selected-source-113","featureId":611,"packId":"ecommerce.progression.support-triage","points":1,"role":"feature","source":"scenarios/progression-support-triage.json","stableKey":"ecommerce.progression.support-triage.support-priority.611b"},{"category":"feature","checkGroupId":"support-status","criterionId":"611c","description":"staff can change a ticket status","executionId":"selected-source-113","featureId":611,"packId":"ecommerce.progression.support-triage","points":1,"role":"feature","source":"scenarios/progression-support-triage.json","stableKey":"ecommerce.progression.support-triage.support-status.611c"}],"components":{"fixture":{"id":"ecommerce.operations","path":"composition/fixtures/operations.json","sha256":"d06444b72dc94fe1ef5e08867d875e1f3bbaa5cd82c35a3558f399c1fcb5ceae"},"packs":[{"id":"ecommerce.feature.accounts","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/feature-accounts.json","requiresPacks":[],"sha256":"9eec7949c45ab6af816008b41245dd1e13e9164a6e10d42895eb93ad40664fbf"},{"id":"ecommerce.feature.bundle-checkout","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/feature-bundle-checkout.json","requiresPacks":["ecommerce.feature.product-bundles","ecommerce.l3.reservations-features"],"sha256":"2905f7ee7d8ae6d1086d2194649242b68ef871d10ec60e1bc0382baf5cb6e7df"},{"id":"ecommerce.feature.bundle-returns","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/feature-bundle-returns.json","requiresPacks":["ecommerce.feature.bundle-checkout","ecommerce.l3.order-returns-features"],"sha256":"c0f9424066d11efd12bf2c88ec3607ac1152ba5b1e34d7fe598529c03035e352"},{"id":"ecommerce.feature.cart","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/feature-cart.json","requiresPacks":["ecommerce.feature.accounts","ecommerce.feature.catalog-items"],"sha256":"217d2a7af92bc0551e17c12376b15668431619cc42f919f9d5a0a709f11eba78","stableId":"ecommerce.feature.cart-checkout"},{"id":"ecommerce.feature.catalog-discovery","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/feature-catalog-discovery.json","requiresPacks":["ecommerce.feature.catalog-items"],"sha256":"9aeea0db86cdacc386e5a26fed12b5604d674047c57c792e9aac3a5eabf14b42","stableId":"ecommerce.feature.catalog"},{"id":"ecommerce.feature.catalog-items","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/feature-catalog-items.json","requiresPacks":[],"sha256":"fce1929f7932d508f463793be463896fbb13ad6da2b7c57e0838188579f7a95f","stableId":"ecommerce.feature.catalog"},{"id":"ecommerce.feature.checkout","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/feature-checkout.json","requiresPacks":["ecommerce.feature.cart"],"sha256":"660aaf39db20b4fd6e405948b45f816c6733a2be37b8190b989a4d18c59eb214","stableId":"ecommerce.feature.cart-checkout"},{"id":"ecommerce.feature.product-bundles","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/feature-product-bundles.json","requiresPacks":["ecommerce.progression.catalog-management"],"sha256":"e768568827d4febae15fe2ec1d25410d86f78ada77debf9cb047d70fe3fdb12c"},{"id":"ecommerce.feature.purchasing","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/feature-purchasing.json","requiresPacks":["ecommerce.feature.accounts","ecommerce.feature.catalog-items"],"sha256":"d21746b5e7246b1771ee9f72d0cc66ef2c2cc9573485ffc839f6ca4b1b01ddff"},{"id":"ecommerce.feature.reviews","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/feature-reviews.json","requiresPacks":["ecommerce.feature.accounts","ecommerce.feature.catalog-items","ecommerce.feature.purchasing"],"sha256":"385771e4c68dbc7afbc0d68af897d698a66f744f50e4f580a813db580cf4615c"},{"id":"ecommerce.feature.split-tender-refunds","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/feature-split-tender-refunds.json","requiresPacks":["ecommerce.feature.store-credit","ecommerce.l3.order-returns-features","ecommerce.progression.support-refunds"],"sha256":"8d12162887644dc6bca1fbcccfd06ebd679bd8017b9234cc5632e6a1f508eba8"},{"id":"ecommerce.feature.store-credit","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/feature-store-credit.json","requiresPacks":["ecommerce.progression.payment-records","ecommerce.progression.staff-roles"],"sha256":"f252e74cb95d87a6a7cec629d59bc7a37cac133e6abee255738ff9a1fca50fcd"},{"id":"ecommerce.feature.subscriptions","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/feature-subscriptions.json","requiresPacks":["ecommerce.progression.payment-records"],"sha256":"31bbe7f11ac99af6eeeeadcd62c49bc635bb20384a6b5e3724b8ba9124530799"},{"id":"ecommerce.feature.warehouse-admin","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/feature-warehouse-admin.json","requiresPacks":["ecommerce.feature.catalog-items","ecommerce.progression.staff-access"],"sha256":"9230ca4ddfe048fd3903f3b90aee16a4711c6d53fbe37478917b16a6e550d66d"},{"id":"ecommerce.l2.inventory-dashboard","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/l2-inventory-dashboard.json","requiresPacks":["ecommerce.feature.warehouse-admin"],"sha256":"98d6ac14b32e61e976377df4687a13d6a780a0e96d2e49a05ce2a386e4588778","stableId":"ecommerce.inventory-operations"},{"id":"ecommerce.l2.order-cancellation-features","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/l2-order-cancellation-features.json","requiresPacks":["ecommerce.feature.purchasing","ecommerce.feature.warehouse-admin"],"sha256":"21f8663b36ea0871493903776ed32fae619183dc5fc0f74a8c1a5e8bc932f561","stableId":"ecommerce.returns-pricing"},{"id":"ecommerce.l2.price-history-features","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/l2-price-history-features.json","requiresPacks":["ecommerce.progression.catalog-management"],"sha256":"786b9f48b9670aa9cb02a439b7eda2feff11c5163a4d49939c892d604206e924","stableId":"ecommerce.returns-pricing"},{"id":"ecommerce.l2.recommendations","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/l2-recommendations.json","requiresPacks":["ecommerce.feature.cart","ecommerce.feature.purchasing"],"sha256":"a21e16ece7b0c4c6e2f0871428af4e4311ae5a91c46174a7ad644b6b93f2c18b","stableId":"ecommerce.inventory-operations"},{"id":"ecommerce.l2.sales-dashboard","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/l2-sales-dashboard.json","requiresPacks":["ecommerce.feature.purchasing"],"sha256":"5e9b1693dcea799edd672e276257a87ad6d7d88099d60be072e952e22e75ca77","stableId":"ecommerce.inventory-operations"},{"id":"ecommerce.l2.stock-transfers-features","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/l2-stock-transfers-features.json","requiresPacks":["ecommerce.feature.warehouse-admin"],"sha256":"fa9514e71b90d38623ede3aa4108cb8a53ca72ed95fc69858733ad38da7235ad","stableId":"ecommerce.inventory-operations"},{"id":"ecommerce.l3.cart-expiration-features","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/l3-cart-expiration-features.json","requiresPacks":["ecommerce.l3.reservations-features"],"sha256":"38029c5ea6d34974b155ef66c311dc500fcece1f82746cffa57ec5f0695f6a5d","stableId":"ecommerce.l3.cart-expiration"},{"id":"ecommerce.l3.deferred-access-specifications","includeRoles":["guarantee"],"moduleType":"specification","path":"composition/packs/l3-deferred-access-specifications.json","requiresPacks":[],"sha256":"cc47732a893439472253b8e209d653959966ca7be20ef0616ab24f8695096814","stableId":"ecommerce.l3.deferred-access"},{"id":"ecommerce.l3.deferred-durability-specifications","includeRoles":["guarantee"],"moduleType":"specification","path":"composition/packs/l3-deferred-durability-specifications.json","requiresPacks":[],"sha256":"9f5109ceb2a8f5e68df317910cea1911dfe79e8c42de51c83b60b760f4075d76","stableId":"ecommerce.l3.deferred-durability"},{"id":"ecommerce.l3.deferred-integrity-specifications","includeRoles":["guarantee"],"moduleType":"specification","path":"composition/packs/l3-deferred-integrity-specifications.json","requiresPacks":[],"sha256":"1a3d27f25be0b41f87afff3412b6f2c93617a68306309f471e0120d1ea359056","stableId":"ecommerce.l3.deferred-integrity"},{"id":"ecommerce.l3.order-delivery-features","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/l3-order-delivery-features.json","requiresPacks":["ecommerce.l2.order-cancellation-features","ecommerce.progression.fulfilment-queue"],"sha256":"7f86ba1b2a2791ba38ba6abeeee6078b061bdf03ea951647d79a74f6fe435b95","stableId":"ecommerce.l3.order-delivery"},{"id":"ecommerce.l3.order-returns-features","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/l3-order-returns-features.json","requiresPacks":["ecommerce.feature.warehouse-admin","ecommerce.l3.order-delivery-features"],"sha256":"cd5dc23d3c7514df91d0a54d92d97e7604e6828b1a287d0c79c714724cdc2206","stableId":"ecommerce.returns-pricing"},{"id":"ecommerce.l3.reservations-features","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/l3-reservations-features.json","requiresPacks":["ecommerce.feature.checkout","ecommerce.feature.warehouse-admin"],"sha256":"972b14948d5dea26cadab3567fc5bbd2c42d4feed5c428c004117b723acecd12","stableId":"ecommerce.l3.reservations"},{"id":"ecommerce.l3.scheduled-restocks-features","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/l3-scheduled-restocks-features.json","requiresPacks":["ecommerce.feature.warehouse-admin"],"sha256":"305c2cf78bc84c63b20cb3e5531760174355128332a365d741dbbd0d64c938cb","stableId":"ecommerce.l3.scheduled-restocks"},{"id":"ecommerce.l3.server-time-specifications","includeRoles":["guarantee"],"moduleType":"specification","path":"composition/packs/l3-server-time-specifications.json","requiresPacks":[],"sha256":"75ad830a0023bf1fe8022695f0776854d75cdbd87f5120a25312c7de33bf57c9","stableId":"ecommerce.l3.server-time"},{"id":"ecommerce.progression.automatic-reorder","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/progression-automatic-reorder.json","requiresPacks":["ecommerce.feature.purchasing","ecommerce.l3.scheduled-restocks-features","ecommerce.progression.staff-roles"],"sha256":"a1d14fcb9cd6c9e96b71d2bacdd4865badaeda913ba9cb3cb5fab8f1eb8497e7"},{"id":"ecommerce.progression.cancellation-accounting-specifications","includeRoles":["guarantee"],"moduleType":"specification","path":"composition/packs/progression-cancellation-accounting-specifications.json","requiresPacks":[],"sha256":"29b290a1356e63a9d2e937c7f92ad540403b27ebcef94df15451d12e59ac86cc","stableId":"ecommerce.returns-pricing"},{"id":"ecommerce.progression.cancellation-queue-specifications","includeRoles":["guarantee"],"moduleType":"specification","path":"composition/packs/progression-cancellation-queue-specifications.json","requiresPacks":[],"sha256":"adf9f45a20d13a400a7812fe825a73de6035f980813c19e3698128e49085b58d","stableId":"ecommerce.returns-pricing"},{"id":"ecommerce.progression.cart-recovery","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/progression-cart-recovery.json","requiresPacks":["ecommerce.l3.cart-expiration-features"],"sha256":"ca6d95040f5b81478546b9afedcc428114e795ced11b8364eb2542c258aec794"},{"id":"ecommerce.progression.catalog-management","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/progression-catalog-management.json","requiresPacks":["ecommerce.feature.catalog-discovery","ecommerce.progression.staff-roles"],"sha256":"f12e7e37d031f470683ff74671b22c1de08eb8f7fe0e9cf03cbcfb4604dd2f06"},{"id":"ecommerce.progression.customer-profile","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/progression-customer-profile.json","requiresPacks":["ecommerce.feature.accounts"],"sha256":"731eeced13c1053432560d4149d2de29fa2cd2b0051759d705cb36e92ad16bb3"},{"id":"ecommerce.progression.delivery-notifications","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/progression-delivery-notifications.json","requiresPacks":["ecommerce.l3.order-delivery-features","ecommerce.progression.notification-preferences"],"sha256":"60b58c4327d74f710f94ffc0deae1b51ef40ca1d2146e45b8e02d1b28e1146bc"},{"id":"ecommerce.progression.faceted-search","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/progression-faceted-search.json","requiresPacks":["ecommerce.feature.catalog-discovery"],"sha256":"5a967859348f967bdc43e0e2490289a859f568e4e8d809c21d5f4404d85e4dd7"},{"id":"ecommerce.progression.fulfilment-queue","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/progression-fulfilment-queue.json","requiresPacks":["ecommerce.feature.purchasing","ecommerce.feature.warehouse-admin"],"sha256":"811eeb166f261e32b5338e118b0851aa1ffeb06b3107dafb6861057e11004db4","stableId":"ecommerce.operations-access"},{"id":"ecommerce.progression.inventory-conservation-specifications","includeRoles":["guarantee"],"moduleType":"specification","path":"composition/packs/progression-inventory-conservation-specifications.json","requiresPacks":[],"sha256":"b3bff8b33e6069bf3cfd2e68389bbd50f0ec9c981d766fd2d7717dcf892463dc","stableId":"ecommerce.inventory-operations"},{"id":"ecommerce.progression.managed-support","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/progression-managed-support.json","requiresPacks":["ecommerce.progression.support-history","ecommerce.progression.support-triage"],"sha256":"6546f37be296605cad2e06bbe71d0cf014d1025a5a4b3b8997f4c38cf6329841"},{"id":"ecommerce.progression.notification-preferences","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/progression-notification-preferences.json","requiresPacks":["ecommerce.feature.accounts"],"sha256":"e8423fe1a2a615a1f2b5bd7073e9cc7040c8d2e2eadc0ef466d50e5d21aaf134"},{"id":"ecommerce.progression.operations-access-specifications","includeRoles":["guarantee"],"moduleType":"specification","path":"composition/packs/progression-operations-access-specifications.json","requiresPacks":[],"sha256":"796806b8a647fd367f53f6246d51aa998b9aa9e2a8959356d237b6411be96937","stableId":"ecommerce.operations-access"},{"id":"ecommerce.progression.order-support","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/progression-order-support.json","requiresPacks":["ecommerce.feature.purchasing","ecommerce.progression.managed-support"],"sha256":"1e1a1722adc4c72fdbf31aa34261b73975df53ffab27b28134d71b09ada1b27f"},{"id":"ecommerce.progression.payment-records","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/progression-payment-records.json","requiresPacks":["ecommerce.feature.checkout","ecommerce.feature.purchasing"],"sha256":"f9203b2def92ee787077b88ae9e31425c03cff7b43a039823c160bc69303cc3f"},{"id":"ecommerce.progression.personalized-recommendations","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/progression-personalized-recommendations.json","requiresPacks":["ecommerce.l2.recommendations"],"sha256":"fafda848a453566e61af3513659a8884979ae49218e490830774bb4c25f7b383"},{"id":"ecommerce.progression.price-accounting-specifications","includeRoles":["guarantee"],"moduleType":"specification","path":"composition/packs/progression-price-accounting-specifications.json","requiresPacks":[],"sha256":"f49fa571d5e63617537742620e92e95a9671ee87f52fd1abc15c2daaf2a6a195","stableId":"ecommerce.returns-pricing"},{"id":"ecommerce.progression.price-history-specifications","includeRoles":["guarantee"],"moduleType":"specification","path":"composition/packs/progression-price-history-specifications.json","requiresPacks":[],"sha256":"5882d2b0daee49ff6f3b8b6aace9fd63f6dca52b18f4dc72f8329e59ffcb9664","stableId":"ecommerce.returns-pricing"},{"id":"ecommerce.progression.promotion-checkout","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/progression-promotion-checkout.json","requiresPacks":["ecommerce.feature.checkout","ecommerce.progression.promotion-rules"],"sha256":"ead1c8b0ab75a29bc55eaf71ceb216f881655ce20321dc0e36ee8e72271383a9"},{"id":"ecommerce.progression.promotion-reporting","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/progression-promotion-reporting.json","requiresPacks":["ecommerce.progression.promotion-checkout"],"sha256":"a0c28a936e0929584ccf418dbbe5f53ba6b6beccd33a5a8255bbfb334a3ddca8"},{"id":"ecommerce.progression.promotion-rules","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/progression-promotion-rules.json","requiresPacks":["ecommerce.feature.catalog-items","ecommerce.progression.staff-access"],"sha256":"4275d81b85379c0030abd92208b732f616a53a2bad8054e0ee6c7f745488105c"},{"id":"ecommerce.progression.recommendation-feedback","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/progression-recommendation-feedback.json","requiresPacks":["ecommerce.progression.personalized-recommendations"],"sha256":"e7e703471cb30e8caf6acf89e3a0ad089dcde8d9320ceaf4fba7132add4007e5"},{"id":"ecommerce.progression.review-access-specifications","includeRoles":["guarantee"],"moduleType":"specification","path":"composition/packs/progression-review-access-specifications.json","requiresPacks":[],"sha256":"d89b6e559244faed30648f2ebdb462913c0b882c614ffe51821c1eb446e66d55"},{"id":"ecommerce.progression.staff-access","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/progression-staff-access.json","requiresPacks":[],"sha256":"440a036f482be11c4954abbb478693a995aea0fe0843f1959a641f3ab6733539"},{"id":"ecommerce.progression.staff-activity","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/progression-staff-activity.json","requiresPacks":["ecommerce.progression.catalog-management","ecommerce.progression.staff-roles"],"sha256":"129e48d11c4b24ae94d45350ffc93e190265dd69eb7948fc34c24c49b438db2e"},{"id":"ecommerce.progression.staff-roles","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/progression-staff-roles.json","requiresPacks":["ecommerce.progression.staff-access"],"sha256":"341efe45e33b4e2fd94a19036034963393b6f9d3749c63faf0bbff0415d0ead8"},{"id":"ecommerce.progression.stock-alerts","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/progression-stock-alerts.json","requiresPacks":["ecommerce.feature.warehouse-admin","ecommerce.progression.notification-preferences"],"sha256":"837f8fcb2c0c023704372810efdc8532246df2b795b94b8503f9d17dae415db9"},{"id":"ecommerce.progression.support-history","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/progression-support-history.json","requiresPacks":["ecommerce.feature.accounts","ecommerce.progression.support-intake"],"sha256":"23d9dd3e5132a88f3ed0d1c65afac0f6ca769f886b6fb531718831358699b90a"},{"id":"ecommerce.progression.support-intake","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/progression-support-intake.json","requiresPacks":[],"sha256":"6458979c3421deb9916903854a1889580b122813500e3437c475fd3bf73d7721"},{"id":"ecommerce.progression.support-refunds","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/progression-support-refunds.json","requiresPacks":["ecommerce.l2.order-cancellation-features","ecommerce.progression.order-support"],"sha256":"fd05f39442798d4bae9e96c65230268bd80be46f40a57007ede06d02d5a28e7c"},{"id":"ecommerce.progression.support-triage","includeRoles":["feature"],"moduleType":"feature","path":"composition/packs/progression-support-triage.json","requiresPacks":["ecommerce.progression.staff-access","ecommerce.progression.support-intake"],"sha256":"2c90c09870de8922db55a9fd8a1b07553c60fd3aebc679f3e4ff1649c752df85"},{"id":"ecommerce.spec.access-control","includeRoles":["guarantee"],"moduleType":"specification","path":"composition/packs/spec-access-control.json","requiresPacks":[],"sha256":"e8999511e92036535ee412cee4be2739aceedd565bcee9ef54c291bb0dbeaf48"},{"id":"ecommerce.spec.bundle-integrity","includeRoles":["guarantee"],"moduleType":"specification","path":"composition/packs/spec-bundle-integrity.json","requiresPacks":[],"sha256":"e0ca540f434e643c5ddbe7fb204fe1edad39376c719d48d4d544caef559595f9"},{"id":"ecommerce.spec.concurrency-safety","includeRoles":["guarantee"],"moduleType":"specification","path":"composition/packs/spec-concurrency-safety.json","requiresPacks":[],"sha256":"350390ddaf5b65e1af7e734cb69404940ec8ab7a632d7201d334a25eb06e2e4c"},{"id":"ecommerce.spec.external-data-sync","includeRoles":["guarantee"],"moduleType":"specification","path":"composition/packs/spec-external-data-sync.json","requiresPacks":[],"sha256":"f4c03de56a2e98f3d4ceb35063b9b5624f7842a4ba89915fcadd9c8a267faef2"},{"id":"ecommerce.spec.live-state","includeRoles":["guarantee"],"moduleType":"specification","path":"composition/packs/spec-live-state.json","requiresPacks":[],"sha256":"49d210d3c5a7aed24d5b296d3a63fe18e87cb9d33821c1f2cdd872a8e06e92f3"},{"id":"ecommerce.spec.search-ordering","includeRoles":["guarantee"],"moduleType":"specification","path":"composition/packs/spec-search-ordering.json","requiresPacks":[],"sha256":"f33275ca6a9593135c94170bd262203eaf65d980e6f810c393f6d07a28bffa50"},{"id":"ecommerce.spec.split-tender-refunds","includeRoles":["guarantee"],"moduleType":"specification","path":"composition/packs/spec-split-tender-refunds.json","requiresPacks":[],"sha256":"91ca0be0e80ea7d001cdd9a2959c7b2c00be3b87aeb5dc06c7db8b9d179ead8c"},{"id":"ecommerce.spec.state-durability","includeRoles":["guarantee"],"moduleType":"specification","path":"composition/packs/spec-state-durability.json","requiresPacks":[],"sha256":"df7c5808d25201493e6eafd46e37091a5f3b9d8f70f2c6ac708d59395137019d"},{"id":"ecommerce.spec.store-credit","includeRoles":["guarantee"],"moduleType":"specification","path":"composition/packs/spec-store-credit.json","requiresPacks":[],"sha256":"4d858d568aabb314ad118b3e2b5003e43710585fdbf4a85b71b9971ca636843c"},{"id":"ecommerce.spec.subscriptions","includeRoles":["guarantee"],"moduleType":"specification","path":"composition/packs/spec-subscriptions.json","requiresPacks":[],"sha256":"7dac820cfeec043b619d468be0c6b0d7e022093851e7884ad573a80aeeb468f2"},{"id":"ecommerce.spec.transactional-integrity","includeRoles":["guarantee"],"moduleType":"specification","path":"composition/packs/spec-transactional-integrity.json","requiresPacks":[],"sha256":"3894b3d9967c3cbb65ea3a3d5b0f8eb88f2673c06b9122f75acc945c8ca06f5f"}]},"contentSha256":"104589b973c1e7dd1a2410659759989eb0de08b16efeda3131777f82858a0a8b","executionSha256":"2a95cbdeb0deaca8fc6f07167df3c3dbd36541b845133ba34617fc88d54cbd85","id":"ecommerce.progression-catalog","meaningSha256":"9724c6dc245ca2cc7d19c9f17938c6edcf3a0234ffbf84b4a48bc8f627aa9337","recipeReleaseSchemaVersion":3,"scoring":{"checks":190,"mode":"source-points","points":359},"sequence":null,"sourceManifest":[{"kinds":["fixture"],"path":"composition/fixtures/operations.json","sha256":"d06444b72dc94fe1ef5e08867d875e1f3bbaa5cd82c35a3558f399c1fcb5ceae"},{"kinds":["pack"],"path":"composition/packs/feature-accounts.json","sha256":"9eec7949c45ab6af816008b41245dd1e13e9164a6e10d42895eb93ad40664fbf"},{"kinds":["pack"],"path":"composition/packs/feature-bundle-checkout.json","sha256":"2905f7ee7d8ae6d1086d2194649242b68ef871d10ec60e1bc0382baf5cb6e7df"},{"kinds":["pack"],"path":"composition/packs/feature-bundle-returns.json","sha256":"c0f9424066d11efd12bf2c88ec3607ac1152ba5b1e34d7fe598529c03035e352"},{"kinds":["pack"],"path":"composition/packs/feature-cart.json","sha256":"217d2a7af92bc0551e17c12376b15668431619cc42f919f9d5a0a709f11eba78"},{"kinds":["pack"],"path":"composition/packs/feature-catalog-discovery.json","sha256":"9aeea0db86cdacc386e5a26fed12b5604d674047c57c792e9aac3a5eabf14b42"},{"kinds":["pack"],"path":"composition/packs/feature-catalog-items.json","sha256":"fce1929f7932d508f463793be463896fbb13ad6da2b7c57e0838188579f7a95f"},{"kinds":["pack"],"path":"composition/packs/feature-checkout.json","sha256":"660aaf39db20b4fd6e405948b45f816c6733a2be37b8190b989a4d18c59eb214"},{"kinds":["pack"],"path":"composition/packs/feature-product-bundles.json","sha256":"e768568827d4febae15fe2ec1d25410d86f78ada77debf9cb047d70fe3fdb12c"},{"kinds":["pack"],"path":"composition/packs/feature-purchasing.json","sha256":"d21746b5e7246b1771ee9f72d0cc66ef2c2cc9573485ffc839f6ca4b1b01ddff"},{"kinds":["pack"],"path":"composition/packs/feature-reviews.json","sha256":"385771e4c68dbc7afbc0d68af897d698a66f744f50e4f580a813db580cf4615c"},{"kinds":["pack"],"path":"composition/packs/feature-split-tender-refunds.json","sha256":"8d12162887644dc6bca1fbcccfd06ebd679bd8017b9234cc5632e6a1f508eba8"},{"kinds":["pack"],"path":"composition/packs/feature-store-credit.json","sha256":"f252e74cb95d87a6a7cec629d59bc7a37cac133e6abee255738ff9a1fca50fcd"},{"kinds":["pack"],"path":"composition/packs/feature-subscriptions.json","sha256":"31bbe7f11ac99af6eeeeadcd62c49bc635bb20384a6b5e3724b8ba9124530799"},{"kinds":["pack"],"path":"composition/packs/feature-warehouse-admin.json","sha256":"9230ca4ddfe048fd3903f3b90aee16a4711c6d53fbe37478917b16a6e550d66d"},{"kinds":["pack"],"path":"composition/packs/l2-inventory-dashboard.json","sha256":"98d6ac14b32e61e976377df4687a13d6a780a0e96d2e49a05ce2a386e4588778"},{"kinds":["pack"],"path":"composition/packs/l2-order-cancellation-features.json","sha256":"21f8663b36ea0871493903776ed32fae619183dc5fc0f74a8c1a5e8bc932f561"},{"kinds":["pack"],"path":"composition/packs/l2-price-history-features.json","sha256":"786b9f48b9670aa9cb02a439b7eda2feff11c5163a4d49939c892d604206e924"},{"kinds":["pack"],"path":"composition/packs/l2-recommendations.json","sha256":"a21e16ece7b0c4c6e2f0871428af4e4311ae5a91c46174a7ad644b6b93f2c18b"},{"kinds":["pack"],"path":"composition/packs/l2-sales-dashboard.json","sha256":"5e9b1693dcea799edd672e276257a87ad6d7d88099d60be072e952e22e75ca77"},{"kinds":["pack"],"path":"composition/packs/l2-stock-transfers-features.json","sha256":"fa9514e71b90d38623ede3aa4108cb8a53ca72ed95fc69858733ad38da7235ad"},{"kinds":["pack"],"path":"composition/packs/l3-cart-expiration-features.json","sha256":"38029c5ea6d34974b155ef66c311dc500fcece1f82746cffa57ec5f0695f6a5d"},{"kinds":["pack"],"path":"composition/packs/l3-deferred-access-specifications.json","sha256":"cc47732a893439472253b8e209d653959966ca7be20ef0616ab24f8695096814"},{"kinds":["pack"],"path":"composition/packs/l3-deferred-durability-specifications.json","sha256":"9f5109ceb2a8f5e68df317910cea1911dfe79e8c42de51c83b60b760f4075d76"},{"kinds":["pack"],"path":"composition/packs/l3-deferred-integrity-specifications.json","sha256":"1a3d27f25be0b41f87afff3412b6f2c93617a68306309f471e0120d1ea359056"},{"kinds":["pack"],"path":"composition/packs/l3-order-delivery-features.json","sha256":"7f86ba1b2a2791ba38ba6abeeee6078b061bdf03ea951647d79a74f6fe435b95"},{"kinds":["pack"],"path":"composition/packs/l3-order-returns-features.json","sha256":"cd5dc23d3c7514df91d0a54d92d97e7604e6828b1a287d0c79c714724cdc2206"},{"kinds":["pack"],"path":"composition/packs/l3-reservations-features.json","sha256":"972b14948d5dea26cadab3567fc5bbd2c42d4feed5c428c004117b723acecd12"},{"kinds":["pack"],"path":"composition/packs/l3-scheduled-restocks-features.json","sha256":"305c2cf78bc84c63b20cb3e5531760174355128332a365d741dbbd0d64c938cb"},{"kinds":["pack"],"path":"composition/packs/l3-server-time-specifications.json","sha256":"75ad830a0023bf1fe8022695f0776854d75cdbd87f5120a25312c7de33bf57c9"},{"kinds":["pack"],"path":"composition/packs/progression-automatic-reorder.json","sha256":"a1d14fcb9cd6c9e96b71d2bacdd4865badaeda913ba9cb3cb5fab8f1eb8497e7"},{"kinds":["pack"],"path":"composition/packs/progression-cancellation-accounting-specifications.json","sha256":"29b290a1356e63a9d2e937c7f92ad540403b27ebcef94df15451d12e59ac86cc"},{"kinds":["pack"],"path":"composition/packs/progression-cancellation-queue-specifications.json","sha256":"adf9f45a20d13a400a7812fe825a73de6035f980813c19e3698128e49085b58d"},{"kinds":["pack"],"path":"composition/packs/progression-cart-recovery.json","sha256":"ca6d95040f5b81478546b9afedcc428114e795ced11b8364eb2542c258aec794"},{"kinds":["pack"],"path":"composition/packs/progression-catalog-management.json","sha256":"f12e7e37d031f470683ff74671b22c1de08eb8f7fe0e9cf03cbcfb4604dd2f06"},{"kinds":["pack"],"path":"composition/packs/progression-customer-profile.json","sha256":"731eeced13c1053432560d4149d2de29fa2cd2b0051759d705cb36e92ad16bb3"},{"kinds":["pack"],"path":"composition/packs/progression-delivery-notifications.json","sha256":"60b58c4327d74f710f94ffc0deae1b51ef40ca1d2146e45b8e02d1b28e1146bc"},{"kinds":["pack"],"path":"composition/packs/progression-faceted-search.json","sha256":"5a967859348f967bdc43e0e2490289a859f568e4e8d809c21d5f4404d85e4dd7"},{"kinds":["pack"],"path":"composition/packs/progression-fulfilment-queue.json","sha256":"811eeb166f261e32b5338e118b0851aa1ffeb06b3107dafb6861057e11004db4"},{"kinds":["pack"],"path":"composition/packs/progression-inventory-conservation-specifications.json","sha256":"b3bff8b33e6069bf3cfd2e68389bbd50f0ec9c981d766fd2d7717dcf892463dc"},{"kinds":["pack"],"path":"composition/packs/progression-managed-support.json","sha256":"6546f37be296605cad2e06bbe71d0cf014d1025a5a4b3b8997f4c38cf6329841"},{"kinds":["pack"],"path":"composition/packs/progression-notification-preferences.json","sha256":"e8423fe1a2a615a1f2b5bd7073e9cc7040c8d2e2eadc0ef466d50e5d21aaf134"},{"kinds":["pack"],"path":"composition/packs/progression-operations-access-specifications.json","sha256":"796806b8a647fd367f53f6246d51aa998b9aa9e2a8959356d237b6411be96937"},{"kinds":["pack"],"path":"composition/packs/progression-order-support.json","sha256":"1e1a1722adc4c72fdbf31aa34261b73975df53ffab27b28134d71b09ada1b27f"},{"kinds":["pack"],"path":"composition/packs/progression-payment-records.json","sha256":"f9203b2def92ee787077b88ae9e31425c03cff7b43a039823c160bc69303cc3f"},{"kinds":["pack"],"path":"composition/packs/progression-personalized-recommendations.json","sha256":"fafda848a453566e61af3513659a8884979ae49218e490830774bb4c25f7b383"},{"kinds":["pack"],"path":"composition/packs/progression-price-accounting-specifications.json","sha256":"f49fa571d5e63617537742620e92e95a9671ee87f52fd1abc15c2daaf2a6a195"},{"kinds":["pack"],"path":"composition/packs/progression-price-history-specifications.json","sha256":"5882d2b0daee49ff6f3b8b6aace9fd63f6dca52b18f4dc72f8329e59ffcb9664"},{"kinds":["pack"],"path":"composition/packs/progression-promotion-checkout.json","sha256":"ead1c8b0ab75a29bc55eaf71ceb216f881655ce20321dc0e36ee8e72271383a9"},{"kinds":["pack"],"path":"composition/packs/progression-promotion-reporting.json","sha256":"a0c28a936e0929584ccf418dbbe5f53ba6b6beccd33a5a8255bbfb334a3ddca8"},{"kinds":["pack"],"path":"composition/packs/progression-promotion-rules.json","sha256":"4275d81b85379c0030abd92208b732f616a53a2bad8054e0ee6c7f745488105c"},{"kinds":["pack"],"path":"composition/packs/progression-recommendation-feedback.json","sha256":"e7e703471cb30e8caf6acf89e3a0ad089dcde8d9320ceaf4fba7132add4007e5"},{"kinds":["pack"],"path":"composition/packs/progression-review-access-specifications.json","sha256":"d89b6e559244faed30648f2ebdb462913c0b882c614ffe51821c1eb446e66d55"},{"kinds":["pack"],"path":"composition/packs/progression-staff-access.json","sha256":"440a036f482be11c4954abbb478693a995aea0fe0843f1959a641f3ab6733539"},{"kinds":["pack"],"path":"composition/packs/progression-staff-activity.json","sha256":"129e48d11c4b24ae94d45350ffc93e190265dd69eb7948fc34c24c49b438db2e"},{"kinds":["pack"],"path":"composition/packs/progression-staff-roles.json","sha256":"341efe45e33b4e2fd94a19036034963393b6f9d3749c63faf0bbff0415d0ead8"},{"kinds":["pack"],"path":"composition/packs/progression-stock-alerts.json","sha256":"837f8fcb2c0c023704372810efdc8532246df2b795b94b8503f9d17dae415db9"},{"kinds":["pack"],"path":"composition/packs/progression-support-history.json","sha256":"23d9dd3e5132a88f3ed0d1c65afac0f6ca769f886b6fb531718831358699b90a"},{"kinds":["pack"],"path":"composition/packs/progression-support-intake.json","sha256":"6458979c3421deb9916903854a1889580b122813500e3437c475fd3bf73d7721"},{"kinds":["pack"],"path":"composition/packs/progression-support-refunds.json","sha256":"fd05f39442798d4bae9e96c65230268bd80be46f40a57007ede06d02d5a28e7c"},{"kinds":["pack"],"path":"composition/packs/progression-support-triage.json","sha256":"2c90c09870de8922db55a9fd8a1b07553c60fd3aebc679f3e4ff1649c752df85"},{"kinds":["pack"],"path":"composition/packs/spec-access-control.json","sha256":"e8999511e92036535ee412cee4be2739aceedd565bcee9ef54c291bb0dbeaf48"},{"kinds":["pack"],"path":"composition/packs/spec-bundle-integrity.json","sha256":"e0ca540f434e643c5ddbe7fb204fe1edad39376c719d48d4d544caef559595f9"},{"kinds":["pack"],"path":"composition/packs/spec-concurrency-safety.json","sha256":"350390ddaf5b65e1af7e734cb69404940ec8ab7a632d7201d334a25eb06e2e4c"},{"kinds":["pack"],"path":"composition/packs/spec-external-data-sync.json","sha256":"f4c03de56a2e98f3d4ceb35063b9b5624f7842a4ba89915fcadd9c8a267faef2"},{"kinds":["pack"],"path":"composition/packs/spec-live-state.json","sha256":"49d210d3c5a7aed24d5b296d3a63fe18e87cb9d33821c1f2cdd872a8e06e92f3"},{"kinds":["pack"],"path":"composition/packs/spec-search-ordering.json","sha256":"f33275ca6a9593135c94170bd262203eaf65d980e6f810c393f6d07a28bffa50"},{"kinds":["pack"],"path":"composition/packs/spec-split-tender-refunds.json","sha256":"91ca0be0e80ea7d001cdd9a2959c7b2c00be3b87aeb5dc06c7db8b9d179ead8c"},{"kinds":["pack"],"path":"composition/packs/spec-state-durability.json","sha256":"df7c5808d25201493e6eafd46e37091a5f3b9d8f70f2c6ac708d59395137019d"},{"kinds":["pack"],"path":"composition/packs/spec-store-credit.json","sha256":"4d858d568aabb314ad118b3e2b5003e43710585fdbf4a85b71b9971ca636843c"},{"kinds":["pack"],"path":"composition/packs/spec-subscriptions.json","sha256":"7dac820cfeec043b619d468be0c6b0d7e022093851e7884ad573a80aeeb468f2"},{"kinds":["pack"],"path":"composition/packs/spec-transactional-integrity.json","sha256":"3894b3d9967c3cbb65ea3a3d5b0f8eb88f2673c06b9122f75acc945c8ca06f5f"},{"kinds":["recipe"],"path":"composition/recipes/progression-catalog.json","sha256":"a869c95b1d5a222dc679d1529a789d623be3d0a82beff818e6b94702a1791ee9"},{"kinds":["contract-source"],"path":"contracts/accounts.md","sha256":"19b453ded62710d998bce1b169497342209feefccd9c4b1cef3bbb9442f01488"},{"kinds":["contract-source"],"path":"contracts/application-interface.md","sha256":"b770db6c1dbf92c106c7501a17028876a30a63655c8f88b5667b44557f401692"},{"kinds":["contract-source"],"path":"contracts/bundle-checkout.md","sha256":"2c4e70b620934dc927ad4c84c17e54b6e9cef665ba3b098f9f2fc9e79a3c4c3e"},{"kinds":["contract-source"],"path":"contracts/bundle-returns.md","sha256":"69f8bf6afc325a98bab38235e49eaa2875bc674e6a61c7559692593018c9f527"},{"kinds":["contract-source"],"path":"contracts/cart-expiration.md","sha256":"56c0966494cd19b629140f8b8d53e8b9838e34668a5cab6b7cccb41b78734c50"},{"kinds":["contract-source"],"path":"contracts/cart.md","sha256":"bb1b8741b9eb47b5766a330bb1fc23005f7540fdc79d20efdaefb183cf50918d"},{"kinds":["contract-source"],"path":"contracts/catalog-discovery.md","sha256":"d13ea495f78e3827b7a243b97466aefbf0252980c76edb432b6b0506854e8450"},{"kinds":["contract-source"],"path":"contracts/catalog-items.md","sha256":"596ec08b1f4a6b290595570f3bcf2847a1f60feeb20d90f98d25761666bfe9f2"},{"kinds":["contract-source"],"path":"contracts/catalog-management.md","sha256":"5123971185ded331deaef2e323fad31e6133d55fc839289e2c4a0dfc5292ee4e"},{"kinds":["contract-source"],"path":"contracts/checkout.md","sha256":"49416683e06d996a28980ff650a3281f89cae062269b7de761899e71759c731c"},{"kinds":["contract-source"],"path":"contracts/customer-profile.md","sha256":"7451bf14ada950c9b7ad269d63467154c388e9ea18b97f479037cdd397ca519f"},{"kinds":["contract-source"],"path":"contracts/delivery-notifications.md","sha256":"4bf565ea751bb5278bae5910420beeb531a2eb88fb5755e5a06dda68860af490"},{"kinds":["contract-source"],"path":"contracts/faceted-search.md","sha256":"08ace4d2d1947f16ceb4da95e6993086c9bd77a0977c258fef1f0a96c7e7879d"},{"kinds":["contract-source"],"path":"contracts/inventory-dashboard.md","sha256":"8c3de4ff8a958776ca087febbbbf5f950eaef9efacb96b7c4fa49357b2d0a371"},{"kinds":["contract-source"],"path":"contracts/managed-support.md","sha256":"458b89a7f786086a95957c778943660068cd6c00b30635fd1cd786c37df76398"},{"kinds":["contract-source"],"path":"contracts/notification-preferences.md","sha256":"d6b4231f67d5e70a03ec331545b6419acf766b52841c8520b94963c16aa13fec"},{"kinds":["contract-source"],"path":"contracts/operations-access.md","sha256":"fd9c31482b484dc1f9bf3c521d247971334e1f52f51a7548a987bdebc65dbdb5"},{"kinds":["contract-source"],"path":"contracts/order-cancellation.md","sha256":"fc274b1409c50de8edcf797ab83cf8e8c46a54db30ada859f854e1cd40c7dee1"},{"kinds":["contract-source"],"path":"contracts/order-data.md","sha256":"7b7cfc6b102f4836235c7f23344865f60156b3e4ac96c3e5cbb0e298390b3b06"},{"kinds":["contract-source"],"path":"contracts/order-delivery.md","sha256":"74bd21b39c8d5f020ff62cc408992c15788e48eba8e05a76a0cddc4b4920a98e"},{"kinds":["contract-source"],"path":"contracts/order-returns.md","sha256":"fe0668ab3bf00d4c167794dbecb75b26b23cb62dfc0a1b79636a013edb237329"},{"kinds":["contract-source"],"path":"contracts/order-support.md","sha256":"a2901e66af870055b6c3c26f240132ae08f3cb93d0c52a7b2573c9dc153e1e03"},{"kinds":["contract-source"],"path":"contracts/payment-records.md","sha256":"8c752352c7f47a0a65d1823f9ec74009dc95088fc6c2a6cc30d1a1dc7fa11fe0"},{"kinds":["contract-source"],"path":"contracts/price-history-orders.md","sha256":"c3a86a7de94e345c578d6b9ba3527c82c137797f385ca4aca3cf2b7ee39b9d40"},{"kinds":["contract-source"],"path":"contracts/price-history.md","sha256":"3465714f91e0e978607900b19377a134e9beb704848e2462b1438465cc2e98ee"},{"kinds":["contract-source"],"path":"contracts/product-bundles.md","sha256":"b27905002b693e6c63532cd8193c8e3fd1fdeaad85041d84b8240a2092bf1c57"},{"kinds":["contract-source"],"path":"contracts/progression-automatic-reorder.md","sha256":"3e70361965e6ddeb7b05cc7ad5348e363d58d628734de96b8a9792e68e71cc72"},{"kinds":["contract-source"],"path":"contracts/progression-cart-recovery.md","sha256":"daf04aea3082483caa2ebf3a3c89a438329600cb6aa5d74fb47d97bc244e5747"},{"kinds":["contract-source"],"path":"contracts/progression-personalized-recommendations.md","sha256":"42389a6d284dcfdb53a610ce5ce77d40dbc2b9d5e177bbd3f6bccc40079c7d98"},{"kinds":["contract-source"],"path":"contracts/promotion-checkout.md","sha256":"b74e703dc77c9eeec26f5beb41cab102570c8314d817015c858557e9946293aa"},{"kinds":["contract-source"],"path":"contracts/promotion-reporting.md","sha256":"81cded5fd9a8822c8756ea50bedb879971c94f8727d176f22fa53d2a6a1efbb0"},{"kinds":["contract-source"],"path":"contracts/promotion-rules.md","sha256":"f352f8bb938aa874125b10bbb6182643f04b6d1ce82cde41512bd16835a7b90b"},{"kinds":["contract-source"],"path":"contracts/purchasing.md","sha256":"c2d59da67b400d055ab90bf53f2e46a3af9605a1fc68534c2b64d8db2ed3409c"},{"kinds":["contract-source"],"path":"contracts/recommendation-feedback.md","sha256":"00a96f594c8da1ffb4a933c6f8d8d0219216ab6cc2c781cfd17dd9c97c517d58"},{"kinds":["contract-source"],"path":"contracts/recommendations.md","sha256":"ab5417cbf78f43464e82a543e50e9601580bb2b3a57826a9e73da9899f39de16"},{"kinds":["contract-source"],"path":"contracts/reservations.md","sha256":"e1c4af7a67dd200d5f18d550e5b4c30e7a4bbaf60600b434108ebff7bdf90627"},{"kinds":["contract-source"],"path":"contracts/reviews.md","sha256":"6be3567258c0c4bf3331e609f63be26ad0bb43ceca3e7da4accaaad8c9ac6541"},{"kinds":["contract-source"],"path":"contracts/sales-dashboard.md","sha256":"ff9ed3890aa5c8303a0badecf946e7d98da3fbbb0a2890a693099bab1a2056c0"},{"kinds":["contract-source"],"path":"contracts/scheduled-restocks.md","sha256":"a946c0954a641d4fe64b933761e2b92d546ae08ee434d676c6faed3ed8b03c8e"},{"kinds":["contract-source"],"path":"contracts/split-tender-refunds.md","sha256":"62b8b3c233d33858e9b696d06d94c70f6524f8cbed77028acc0d2affdd780841"},{"kinds":["contract-source"],"path":"contracts/staff-access.md","sha256":"dcd7b740d5f65160ddf0b4221d29f84426ee89f04560e953add0856cf0bca87a"},{"kinds":["contract-source"],"path":"contracts/staff-activity.md","sha256":"7e7c1846445f82aa78ad8e32606e6830f9d326ebfea75d13b077c073695c9594"},{"kinds":["contract-source"],"path":"contracts/staff-roles.md","sha256":"cce6145182485fafcd2adc29cec90af20523a2afd9c952800eefb5d15a49f96e"},{"kinds":["contract-source"],"path":"contracts/stock-alerts.md","sha256":"405f106569c84b3062f8159452730f16adadf12d804c554a570e39b958b63421"},{"kinds":["contract-source"],"path":"contracts/stock-transfers.md","sha256":"01f28ebb3487559d4689919f0991e43f74fcc85609fa4c810e92adde30e84096"},{"kinds":["contract-source"],"path":"contracts/store-credit.md","sha256":"505ca48dfc4f9f2d6ea38e53e1bd382910264d0195be8580b5fb01f7e7074713"},{"kinds":["contract-source"],"path":"contracts/subscriptions.md","sha256":"dc533bc7f3b9be03ae7d9e18c2e02ffa996bf934b9ba230826d492b4cefa045e"},{"kinds":["contract-source"],"path":"contracts/support-history.md","sha256":"610022f964c2aa00b409fb2723f91b885e306edde5bf73390e880cffd2a5583d"},{"kinds":["contract-source"],"path":"contracts/support-intake.md","sha256":"fd9f732acf67d6c772f4c05d626e4e9e472818fc5226b7ef3d7223b85a0e0bc7"},{"kinds":["contract-source"],"path":"contracts/support-refunds.md","sha256":"da5d0e69bbf3a028dc79f207b940bbd4a79e7f82c68d89f252eb8c73ea16b8bc"},{"kinds":["contract-source"],"path":"contracts/support-triage.md","sha256":"8079080a299674bb0558a6550243051360be1c0f18252708128c3f71af899a0d"},{"kinds":["contract-source"],"path":"contracts/warehouse-administration.md","sha256":"ea037935ce439d10f4ccea3296bb16aa2ddee4e0c13b2b7ade0638ff7cb9b8d6"},{"kinds":["requirement-source"],"path":"prompts/modular/accounts.md","sha256":"0a8dee0847a02da7777c11c4175577c4533fafa538fc09e5124cf4d825e4c96f"},{"kinds":["requirement-source"],"path":"prompts/modular/bundle-checkout.md","sha256":"d3f21ac08991619b5c9aa6ac99a7554340bae991d5b31a25cdb048cdb314936e"},{"kinds":["requirement-source"],"path":"prompts/modular/bundle-returns.md","sha256":"34b3bee882e6a1f6a1527e67d12f8cbdcfd74d026108f9805159123c41015bf2"},{"kinds":["requirement-source"],"path":"prompts/modular/cancellation-conservation.md","sha256":"f383c20f16d75b77dfe2c0ca10dc1c77c998feb80b7c327616512b486c4714f8"},{"kinds":["requirement-source"],"path":"prompts/modular/cancellation-queue.md","sha256":"7e1adf98391a930017acb5c37d46c9b0d17d89e58c939fc57dc52f22e2f86f31"},{"kinds":["requirement-source"],"path":"prompts/modular/cart-expiration.md","sha256":"7c66696f044249d5f7f31487efb85e83f4c06b862fbaa3dd142ef2aef6afc2b7"},{"kinds":["requirement-source"],"path":"prompts/modular/cart.md","sha256":"da024de4032661a46574c8ac8dbe3d1baf45ef6ea7115ba1976d7d5c1044afbe"},{"kinds":["requirement-source"],"path":"prompts/modular/catalog-discovery.md","sha256":"9a0785c55d17e577b84ef257de482bcd8bc8c961e9d0760c38472936a1a0062b"},{"kinds":["requirement-source"],"path":"prompts/modular/catalog-items.md","sha256":"36a72da77f42d856b691c93dc587fee6d9d7f88b722a9893fc226b1d5bb5d3fe"},{"kinds":["requirement-source"],"path":"prompts/modular/catalog-management.md","sha256":"93fece29e1d68513732398c815fe4ebc83079e705e2b9de40df543281439f390"},{"kinds":["requirement-source"],"path":"prompts/modular/checkout-recovery-specification.md","sha256":"0e851fea800d81cb558f8004f04e628e5ccf9f6e5589a9d2f6fceaf33e50f207"},{"kinds":["requirement-source"],"path":"prompts/modular/checkout.md","sha256":"bb834dec7858349a17a8980eb13459a606cdbd2b1c534f468f666459c1a24ba7"},{"kinds":["requirement-source"],"path":"prompts/modular/customer-profile.md","sha256":"f4ffc5d2a642bbccec9eb5c428a37b2d9bfaa1c9f96648d8544bfcf2fe8187bb"},{"kinds":["requirement-source"],"path":"prompts/modular/delivery-notifications.md","sha256":"12d6db9061749779dcb3db699a492781b34ae955c4c11cbb3e5dc2c8e0300ef3"},{"kinds":["requirement-source"],"path":"prompts/modular/faceted-search.md","sha256":"5dc13b47abcbc85654c82148f44b854979d868578db50db42e060c773edc2207"},{"kinds":["requirement-source"],"path":"prompts/modular/inventory-dashboard.md","sha256":"d2190c809ce459141cfdb716d25d38b01f7aca2ce8b8f74128e731e4e3fede07"},{"kinds":["requirement-source"],"path":"prompts/modular/l1-external-sync-specifications.md","sha256":"7f0486045ef1b18271d1b004515f3a1dbf76d09ed62eb7c0683b099100b7f903"},{"kinds":["requirement-source"],"path":"prompts/modular/l1-specifications.md","sha256":"bc3ab63f33d9bbc59fde776c7fdc83ecfdf3d087be78e2596538b7d6945fdd8a"},{"kinds":["requirement-source"],"path":"prompts/modular/l3-specifications.md","sha256":"e6b9877c0f28ec287e510367a810221d09f9b48bb506f7c3cde4eb4450a3eaf4"},{"kinds":["requirement-source"],"path":"prompts/modular/later-specifications.md","sha256":"097745468f48a0589fd9dd81ad98d3ca0ce9455678156fc74d2331e403a77a39"},{"kinds":["requirement-source"],"path":"prompts/modular/managed-support.md","sha256":"33abfe9e7514c6826df60572557d54f2e1570477afeae14c64bb3c5f3bad5fb6"},{"kinds":["requirement-source"],"path":"prompts/modular/notification-preferences.md","sha256":"496baa70ef300e6874f6dbf58ccd2bac594e53101875fd68740e27779d11871b"},{"kinds":["requirement-source"],"path":"prompts/modular/operations-access.md","sha256":"1699a8d0466e115874e49b8ae73bb0004c3c620a03d3aa04dd83818b6c798003"},{"kinds":["requirement-source"],"path":"prompts/modular/order-accounting.md","sha256":"c83044972a6f53a723dcba9ef9dec157eeacb4d2059b790a426da255134364d0"},{"kinds":["requirement-source"],"path":"prompts/modular/order-cancellation.md","sha256":"7d429d4e8db546961e7ec9a12fb5dcba5efd0562c8059ab354121fd5ed13ea84"},{"kinds":["requirement-source"],"path":"prompts/modular/order-delivery.md","sha256":"40483d0bf91c81efe57a61d62dbda756498792383bed9af595cdd8878a0b0cb8"},{"kinds":["requirement-source"],"path":"prompts/modular/order-ownership.md","sha256":"1f4e5149768d1d0a4917ca9b711f1f40bf2c783ee5d59a42ab307f01babb052e"},{"kinds":["requirement-source"],"path":"prompts/modular/order-returns.md","sha256":"7277266f1e8c7d660ee38ba55ac1359200e56c695862c6d7d755d6ec6a6cb808"},{"kinds":["requirement-source"],"path":"prompts/modular/order-support.md","sha256":"f515fe9827373e110633245df158ce8f78ca040f6c25a059d3885182515abb9a"},{"kinds":["requirement-source"],"path":"prompts/modular/payment-records.md","sha256":"ab5c9c913041e324cad82fe6a135d78906818afa3c9a5c204289142c1d696f09"},{"kinds":["requirement-source"],"path":"prompts/modular/price-authorization.md","sha256":"6e9f949bd45f3bc816336de6e7db6dd18254ceebe6ecacc8e0abfd5f3887b8b5"},{"kinds":["requirement-source"],"path":"prompts/modular/price-history-orders.md","sha256":"005e1db32c0c5e4c4f52c1834f82c3d35c7118912c86580b4295a34e9ff12d3e"},{"kinds":["requirement-source"],"path":"prompts/modular/price-history.md","sha256":"9edb3db98af12f3a08cae7887dd6da91c746be49597f086457fc2ecb70c558b8"},{"kinds":["requirement-source"],"path":"prompts/modular/product-bundles.md","sha256":"a0805178ebbb20ea290994de65b4ded503c37798af59905d47c1cb2fd4e2c467"},{"kinds":["requirement-source"],"path":"prompts/modular/production-specifications.md","sha256":"a49cc5aae32bfb035b878e297ee67c1aa8b83ca90e7c73c3dd0cf9f919ae1cf6"},{"kinds":["requirement-source"],"path":"prompts/modular/progression-automatic-reorder.md","sha256":"64751064e699c709a6550daba6fee8f019f445b817910e1ed0d8831632fa2471"},{"kinds":["requirement-source"],"path":"prompts/modular/progression-cart-recovery.md","sha256":"4dc64aaa87d54a05bd7cce31bdc98254e605251d14f1688b859e9aa908da6a8b"},{"kinds":["requirement-source"],"path":"prompts/modular/progression-framing.md","sha256":"33042f5721843cd3796c8545c2a01a32e6d9b341192036321f6532f5ed0e03d2"},{"kinds":["requirement-source"],"path":"prompts/modular/progression-personalized-recommendations.md","sha256":"6c78b3963318b18da11173f96bed5cb8e5537f49e0008342ff11209fada3e099"},{"kinds":["requirement-source"],"path":"prompts/modular/promotion-checkout.md","sha256":"1979ce8991b38fab30c4ea0d0fb7adba51d79bb82981059b0dafded82fed843a"},{"kinds":["requirement-source"],"path":"prompts/modular/promotion-reporting.md","sha256":"3285eb0a50ceeed40b3415bdab8d6f5fc4138e496d2062a08c5ee2fac70157c6"},{"kinds":["requirement-source"],"path":"prompts/modular/promotion-rules.md","sha256":"7a43b632e8fd43b8060100f9614476e41003e47afa04dd1b7c3b09639f6280b2"},{"kinds":["requirement-source"],"path":"prompts/modular/purchasing.md","sha256":"059073391cf92eef2fb1edb710ec1a62747e82115c2bd0251274111b92f93e46"},{"kinds":["requirement-source"],"path":"prompts/modular/recommendation-feedback.md","sha256":"072a548ae797773041e86cbc62f39011559ca7ab40441bee6b77ec1854cd7f51"},{"kinds":["requirement-source"],"path":"prompts/modular/recommendations.md","sha256":"0eed3feb6fc6acf86260d74eeff557b15837aaa09a857c63cf9dee848cd7201f"},{"kinds":["requirement-source"],"path":"prompts/modular/reservations.md","sha256":"e45b53568066c7200486453f78fdbbe89a116259a4d83d9435bde350316595e0"},{"kinds":["requirement-source"],"path":"prompts/modular/review-access.md","sha256":"430fe60b2f028f67eab9f23b572238d4dacc60f7b89d74f8030618368455f371"},{"kinds":["requirement-source"],"path":"prompts/modular/reviews.md","sha256":"1649822528e1bbcfedc59b3c8c5d7ff1b5f0e42e1e82b81ee7e59361cbefab33"},{"kinds":["requirement-source"],"path":"prompts/modular/sales-dashboard.md","sha256":"c65aaadb1f8da6e2b5f7967cc3bcf07beb0e7a860351e866373667bc33012dbd"},{"kinds":["requirement-source"],"path":"prompts/modular/scheduled-restocks.md","sha256":"ba32547038c681f7214219e5a10df75dbf925ee19d4ba60db5b291570f9c16ec"},{"kinds":["requirement-source"],"path":"prompts/modular/search-ordering-specification.md","sha256":"77d88f2b03c71b6cdc8350020ffd7815cf0bee87e4155c1aa00beb9bb81a83f8"},{"kinds":["requirement-source"],"path":"prompts/modular/shipping-authorization.md","sha256":"f336e9c8e1ea425c3dc44e72fabbc5e9e0e2a3541cab3750dd8e112b6c7997f8"},{"kinds":["requirement-source"],"path":"prompts/modular/split-tender-refunds.md","sha256":"c21e00af3623136de4ae45f089b45b457a34563eb37a756d5b8b3563d1f19734"},{"kinds":["requirement-source"],"path":"prompts/modular/staff-access.md","sha256":"10c6aedbc5c60b440d6d0b5c38bb57363ae021c54d62ee2ffe2294d7f6741550"},{"kinds":["requirement-source"],"path":"prompts/modular/staff-activity.md","sha256":"0cb274acefc0d75cd82415de0eb167133db0412e1de4f0fd59f62983d29a1476"},{"kinds":["requirement-source"],"path":"prompts/modular/staff-roles.md","sha256":"951f617a191161df8b9061b304ad568bb5a942070e72142ddf4b93c3dd099951"},{"kinds":["requirement-source"],"path":"prompts/modular/stock-alerts.md","sha256":"3478629a2831e04baca5eec1d3a2a3695c03f6044c36b43acb7c8ca7e35e9867"},{"kinds":["requirement-source"],"path":"prompts/modular/stock-conservation.md","sha256":"4551438e045bb65b44127d3f92dcb79548c78dc1ecc42d2c7807a599d6c59c8f"},{"kinds":["requirement-source"],"path":"prompts/modular/stock-transfers.md","sha256":"6e2f0735d81fd5376b851893404873af4807b83e807e078cca0b8c9a9920e627"},{"kinds":["requirement-source"],"path":"prompts/modular/store-credit.md","sha256":"d769da6c0ef4eb2fa6ac241aeddb61e8e2d85a0f1fcfd595fbf2c6660f67cd7b"},{"kinds":["requirement-source"],"path":"prompts/modular/subscriptions.md","sha256":"ca93ab01c0d23c2fb3c035981372dc1254b219f1875b9566c0d01123176cc7c1"},{"kinds":["requirement-source"],"path":"prompts/modular/support-history.md","sha256":"df2ca2664901a90814eab17d5f7c029595ef614d76ee29eeb4204d9f4f371429"},{"kinds":["requirement-source"],"path":"prompts/modular/support-intake.md","sha256":"048f11b71b66dadf80c77b5d9aef8bbff2b2030171eeda5012dce74ae16421ed"},{"kinds":["requirement-source"],"path":"prompts/modular/support-refunds.md","sha256":"79090320de03a74660418da9e9adbf8170f8c574be990faeaf3d7df652221aa6"},{"kinds":["requirement-source"],"path":"prompts/modular/support-triage.md","sha256":"bbb35abcbae9b8d3782ee3eb94f3175428edfe3fa564d6b0e3af2e0050e10dee"},{"kinds":["requirement-source"],"path":"prompts/modular/transfer-authorization.md","sha256":"6d1e33c7a6aa209ad3f2705607a839dde5c915b65d78a8bb10b9e0da29172c0b"},{"kinds":["requirement-source"],"path":"prompts/modular/warehouse-administration.md","sha256":"8fa2d7b54b3c3d9601ae69bbfee5bdf389f68fea0d0ef4032201af12d3f424a2"},{"kinds":["scenario"],"path":"scenarios/01-account-create.json","sha256":"f37b83a76ff787e12aae1c86fa91b5a2483bfb1aef9497c291e2a374a4376f45"},{"kinds":["scenario"],"path":"scenarios/01-account-duplicate.json","sha256":"f699c90ca3b1af3eda1b73e3c38a4a7cce19b779afa2f9b208c9ead6fdbf15ba"},{"kinds":["scenario"],"path":"scenarios/01-account-password.json","sha256":"35ea9a3a824444096d9d0a51388296c7c35fc833a532b5252f1df9fc5cfab125"},{"kinds":["scenario"],"path":"scenarios/01-account-reload.json","sha256":"574de181769f0d2fa1a88f1131b2a033385fdd576f9aa5088e95781cbd2266d4"},{"kinds":["scenario"],"path":"scenarios/01-account-signout.json","sha256":"7ce90ffda1338d99e37a87ea5beecaeaaa56adecbeb2f46707d1cf0934e596d1"},{"kinds":["scenario"],"path":"scenarios/01-admin-write-staff.json","sha256":"caf94ac7cbffea4438a343c0883322e090cf83aad743a882fb747c287c89f2a2"},{"kinds":["scenario"],"path":"scenarios/01-buying.json","sha256":"48168c76a51b5e1e6d15573a0891cf90889f99aab78b638a24892f70c55ff257"},{"kinds":["scenario"],"path":"scenarios/01-cart-boundary.json","sha256":"76b9c484f70ac94f0dc1787a1a4e61851bf6586e8d1facc9f970791d47a81777"},{"kinds":["scenario"],"path":"scenarios/01-cart.json","sha256":"88cd43f3f48ae86eeec891677a2817f42f8f6554bad299cfae92889d00262d3c"},{"kinds":["scenario"],"path":"scenarios/01-catalog-ranking.json","sha256":"05436b81ee1fefb5e781f7a68060d41690bcdb7b1b9cb0e7543d183b738f1e14"},{"kinds":["scenario"],"path":"scenarios/01-catalog-search.json","sha256":"a633a4afcdbc5e19cc3189ab5e93c358fad44672a4ec2570fa4569c0e9ee0d02"},{"kinds":["scenario"],"path":"scenarios/01-catalog-values.json","sha256":"6216be4761d0db8ac4480ad1fa1a6d4a628d3a4c022278eb7ebf25105db50ea2"},{"kinds":["scenario"],"path":"scenarios/01-core.json","sha256":"1d7f0cf801d41fb01a4f63b2a414c9d723b0749130d1eefff84730567f9a1614"},{"kinds":["scenario"],"path":"scenarios/01-duplicate-checkout.json","sha256":"b6f470b48e0f504d479376ec25895c1d9c293b1ab52cc9d27a1f626519513290"},{"kinds":["scenario"],"path":"scenarios/01-external-live-sync.json","sha256":"3a3dbe302f7e300ac7e82d680d6fb7c6ee277ec9e175d590f68c1c86569ab752"},{"kinds":["scenario"],"path":"scenarios/01-external-reconnect-sync.json","sha256":"5a9e3822bf5c888709d8fc6e255c29e429ba52be3460d688b8ce0a77ef72e79c"},{"kinds":["scenario"],"path":"scenarios/01-external-reload-sync.json","sha256":"80d9eeb9995c30ae4af156c3d93d42475e8b7de0c1e7dca69d4f882536a5cf86"},{"kinds":["scenario"],"path":"scenarios/01-external-server-restart-sync.json","sha256":"c4dab98e2623e35045fa9dd9f4d251392adf316c7ccacc41982fe16b9a8aa574"},{"kinds":["scenario"],"path":"scenarios/01-last-unit.json","sha256":"499778db939f0392d5576e9ea8feba62cd3f9d7ae07130283cbc3babebc81405"},{"kinds":["scenario"],"path":"scenarios/01-order-ownership.json","sha256":"6bef82c8e28f962d06479e452b2019bf107e4b89cfcda5a11e927f9c518c647b"},{"kinds":["scenario"],"path":"scenarios/01-purchase-attribution.json","sha256":"6e1974179f5bb3c475fd84dc051b3e6f37cf4e02cde17928bc1a68275ce798cc"},{"kinds":["scenario"],"path":"scenarios/01-purchase-session.json","sha256":"219f67e5959209f89ee7179a584bcde6e8ac340bd121cbeb0e25895604d1c614"},{"kinds":["scenario"],"path":"scenarios/01-restock-race.json","sha256":"d37c5071bdb221db025cbe43c6377cc7eca99c62ee6e4720737a32eb60decffa"},{"kinds":["scenario"],"path":"scenarios/01-review-eligibility.json","sha256":"ad387c41d1902fab24915cf9cdeed8a2cd0d7aae26ffc379ae784e61d5c3a277"},{"kinds":["scenario"],"path":"scenarios/01-review-rating-live.json","sha256":"f6d4d0c9ea3bbd1213d130ee1d706e326ffbab33e5b9fd6633fa6ff90fea3e3c"},{"kinds":["scenario"],"path":"scenarios/01-review-uniqueness.json","sha256":"49873dc6cf26204dcebd1038b71bfc5213b091d3d13f5f37c5980998a7f3f8f6"},{"kinds":["scenario"],"path":"scenarios/01-review-visibility.json","sha256":"81360bc6b9735251c7672ee26148912aebcc1426b0be2eca9eecd5e607b927b8"},{"kinds":["scenario"],"path":"scenarios/01-server-price.json","sha256":"24481cb30af8c57ebb26b2adb393b8987642e60ddecdbeff2c0381c122825fdc"},{"kinds":["scenario"],"path":"scenarios/01-warehouse-admin-staff.json","sha256":"5434bf92e5b343862dfcb0e6b26593a71db86c0635222ebb3101f60e00fbea5a"},{"kinds":["scenario"],"path":"scenarios/01-warehouse-stock-live-staff.json","sha256":"708a7bd1df90dba203d6c1236d83a3e6deaaecb6e69b4c2faa4208f773966414"},{"kinds":["scenario"],"path":"scenarios/02-cancellation-queue.json","sha256":"d8758cc074fec24a5d8d1d4395e2edb2a7f376d14d91427df6f70b9a5e8e49ce"},{"kinds":["scenario"],"path":"scenarios/02-fulfilment-access.json","sha256":"ccd33eb7a0fbf80f71c86c963f3fe747581808622a33f842e3aa85d940c20012"},{"kinds":["scenario"],"path":"scenarios/02-fulfilment-live.json","sha256":"54455bebda5a1ef78421b81229d63298fcddae0a8315379c173cca0436e0638f"},{"kinds":["scenario"],"path":"scenarios/02-fulfilment-ship.json","sha256":"3996ecb875ae0ca32eb68053650d0d415246487aac909c5de901789f39d64913"},{"kinds":["scenario"],"path":"scenarios/02-invariants.json","sha256":"23b929b83386165a6fff61ee3cbe6845d5da66e5707cdc1ce8f5ead3207018b4"},{"kinds":["scenario"],"path":"scenarios/02-live-price.json","sha256":"7a905177cae6af15f682ebdb909f695bdee85d3124ee91917cb65e8209a73803"},{"kinds":["scenario"],"path":"scenarios/02-low-stock.json","sha256":"a985505feaa58e6f80f08865ea08658da174a01d08a1e70b832b5dd8579e5c88"},{"kinds":["scenario"],"path":"scenarios/02-operational-best-sellers.json","sha256":"f887d0f4dd660fb85a80f10d6e6e1c9fcf6f2bf25e79fbbd7ba86227968e8ace"},{"kinds":["scenario"],"path":"scenarios/02-operational-category-totals.json","sha256":"263411fec43db53777309f2d64fcbdeef1b551a2d981ee8aa8b4caa0ea2faa16"},{"kinds":["scenario"],"path":"scenarios/02-operational-recommendations.json","sha256":"7ea0fa0f317f963c9d2d37adef945be9b8f19eb8618f387bda0a5cd6b92f30b1"},{"kinds":["scenario"],"path":"scenarios/02-order-cancellation-core.json","sha256":"a490889daee2a92eeb18eb35cb4050a47df179d02e031286d70848a4f2595787"},{"kinds":["scenario"],"path":"scenarios/02-order-cancellation-history.json","sha256":"304c8eb8477bc63fda3a1d90f11e3a03fd6391001d8a12ec405c14aeaced4ccb"},{"kinds":["scenario"],"path":"scenarios/02-paid-price-history.json","sha256":"84896fdea36b4f267443000306a6a349fc7221772278d96c751516b0330dff5d"},{"kinds":["scenario"],"path":"scenarios/02-queue-warehouse.json","sha256":"212e8e907b85aff9e4047e7f6f4258d3078aa78ac6bc1df21abb980759322cf2"},{"kinds":["scenario"],"path":"scenarios/02-self-contained.json","sha256":"aad3ce91dae1a94c0f230bab33b0c7a7942337db51f4f9cde06d1d9e2cc99300"},{"kinds":["scenario"],"path":"scenarios/02-server-actions.json","sha256":"a4f22b10cd76a69e6d761818668c7ec52ad064a0a5b1c391a30fde95849b7211"},{"kinds":["scenario"],"path":"scenarios/02-strengthened.json","sha256":"15fc5e537422dbe8dd875cae0b82ac5b5afbf4b65d45ff4545aaea38dd8a9db8"},{"kinds":["scenario"],"path":"scenarios/02-transfer-overdraw.json","sha256":"df6655ff0bb3c9553384ac37f3659af66d6153fef05d31db5e3d3a1d8165f096"},{"kinds":["scenario"],"path":"scenarios/02-transfer-totals.json","sha256":"81462d3b8d4e78f2dd0e207faf285dca472974cd2cab95f723ce735fc3a5c589"},{"kinds":["scenario"],"path":"scenarios/03-cart-expiration.json","sha256":"22a10c3255506dd1bd50ab7caef5187bd0fc3bad3400ad4af9221c811b570d40"},{"kinds":["scenario"],"path":"scenarios/03-deferred-access.json","sha256":"91ed336253f239ed05cb74bf639be7d9ec0f29bb9b372261295ea7d9babc7098"},{"kinds":["scenario"],"path":"scenarios/03-deferred-durability.json","sha256":"fc425c650e26f4be6134cfdbf590423073fd9e2ebac5ee852b646df7a599a954"},{"kinds":["scenario"],"path":"scenarios/03-deferred-integrity.json","sha256":"5bc1faefe4b3d2547b19afc8a5fafb8dbbfef05d45dcb71b2979e0777eb0bcb0"},{"kinds":["scenario"],"path":"scenarios/03-order-delivery.json","sha256":"880e518338a1615825595b983daf64c6e1d68db924ad5fd8c1b205df7e3ff1aa"},{"kinds":["scenario"],"path":"scenarios/03-reservations.json","sha256":"c2460d2b1f1336d1e4c918b6c27ac962d680f8df897a8ca8fd52bdbd403d17ca"},{"kinds":["scenario"],"path":"scenarios/03-scheduled-restock-apply.json","sha256":"74f49d25eea210b9e0209a57261809a585ca28380edfd50084933beff743d2c1"},{"kinds":["scenario"],"path":"scenarios/03-scheduled-restock-cancel.json","sha256":"462df740d24017bc487d961b1547cafdf0e2bc1cea7805dc669d68ff245261bc"},{"kinds":["scenario"],"path":"scenarios/03-scheduled-restocks.json","sha256":"510a8b147738a249b30dce4900e431ca32880de5ea990600aca063c38535b228"},{"kinds":["scenario"],"path":"scenarios/03-server-time.json","sha256":"667e580173187cb4b0f9538336a7e12108e14b5273c9ac663faa5f2325b006be"},{"kinds":["scenario"],"path":"scenarios/progression-account-state-reconnect.json","sha256":"1ead0e72e9375a95cd03caa09bd1fefd858bef7bc910dd6762a53bcee968ce55"},{"kinds":["scenario"],"path":"scenarios/progression-account-state-reload.json","sha256":"fd464513460c640ddcec6ed7e30f9c434a982ae300d16f5233551c14bff45995"},{"kinds":["scenario"],"path":"scenarios/progression-automatic-reorder-access.json","sha256":"ed57cd01a22e7b7a964108ccf1f971f2e8877921015fdd952cb28109cb7be32d"},{"kinds":["scenario"],"path":"scenarios/progression-automatic-reorder-duplicate.json","sha256":"41fe868171047997d33fe6f424bf771fff8d91fc32a19ef749510fa6f41abb57"},{"kinds":["scenario"],"path":"scenarios/progression-automatic-reorder.json","sha256":"91827fedd89c2e268b2b9102d62a89d39dc8d4e07af619d82073c07595c10d57"},{"kinds":["scenario"],"path":"scenarios/progression-books-balance.json","sha256":"6f8d35c97296d36f26ebe07b9b6abc7d73531e4dab495c370a13e80d43adde46"},{"kinds":["scenario"],"path":"scenarios/progression-bundle-checkout.json","sha256":"b26a777560d208a1e415b58dfd46b3662669c4546208d141f0954033ff575a2f"},{"kinds":["scenario"],"path":"scenarios/progression-bundle-returns.json","sha256":"e8d4c983cb11934ac323abbe0ddf55715d75a832133bfd664197677da4911ec8"},{"kinds":["scenario"],"path":"scenarios/progression-cart-checkout.json","sha256":"b49e07cca26e9461db2467cfce31eb43c7b10fb1481a7252353f08d31bf67abd"},{"kinds":["scenario"],"path":"scenarios/progression-cart-recovery.json","sha256":"8c00fd1d2d10091754577acab63319dd593c137ccb75bcbb45cb43bf000b8298"},{"kinds":["scenario"],"path":"scenarios/progression-catalog-management.json","sha256":"a18d83be7f697b89976b062112acd31755b93a702e12b2bd0f6de993f1c9b0e4"},{"kinds":["scenario"],"path":"scenarios/progression-checkout-crash.json","sha256":"024b80278cdcb30ac53a448db82b45ada850d7c22a04ace3aecf296f03b2b1ef"},{"kinds":["scenario"],"path":"scenarios/progression-core-business.json","sha256":"deac867579938f0e41fb16c02e302416d5dcbfd2d20d11a7374236d58c35b8c1"},{"kinds":["scenario"],"path":"scenarios/progression-customer-profile.json","sha256":"7590ab78f8f475fb16fe7959e625da404d29f1e58f9ceb11f51f557648b91829"},{"kinds":["scenario"],"path":"scenarios/progression-delivery-notifications.json","sha256":"62a30dc8ec24d1758e49f90cdaf60856cc465136595347550ae78fe880d2a8a6"},{"kinds":["scenario"],"path":"scenarios/progression-faceted-filters.json","sha256":"b4610dc373d96ad2eeba7c38fb33173ec74250d8ef4941897bb3c48a98cb5368"},{"kinds":["scenario"],"path":"scenarios/progression-faceted-pagination.json","sha256":"c27b5edbd219e2f440ffa29dbad77dbe2da3485437ec9c0071c2d8a99017aeee"},{"kinds":["scenario"],"path":"scenarios/progression-managed-support-privacy.json","sha256":"74da98e1252bb77f0c3b8bf2a9ac788acb7a0104405d786c9a65c51048af7aad"},{"kinds":["scenario"],"path":"scenarios/progression-managed-support-shared.json","sha256":"712852c3d0289ca15efe348797449fcc3b301df5d3d0a9150b188623fced206d"},{"kinds":["scenario"],"path":"scenarios/progression-notification-preferences.json","sha256":"cb494fbc2543347407abe54f74d9cc3cc698f135690f063ebbbff756aec8c807"},{"kinds":["scenario"],"path":"scenarios/progression-open-list-live.json","sha256":"9abcf41a6919dab036d26869c75de0129b12814e9d49bcf80653fa6e61eff1b0"},{"kinds":["scenario"],"path":"scenarios/progression-order-return-boundary.json","sha256":"c404ce6d68113bd69e290bfcfae4b72b14c0a19f63de349dcf79e47563b1f255"},{"kinds":["scenario"],"path":"scenarios/progression-order-return-complete.json","sha256":"02c41f76b4bc60ba0b0e624df540fcd77e7407c90a2e66487672ed6f9c5ed9f2"},{"kinds":["scenario"],"path":"scenarios/progression-order-support-boundary.json","sha256":"9f19a26a9e4d4fe4385f94150bdef6c4e16913f79c5b0fbaede02984ce098362"},{"kinds":["scenario"],"path":"scenarios/progression-order-support-owned.json","sha256":"dda5208d3dbe3a151e683a8cd238f414118553ea0812584f00a82655255cf1a5"},{"kinds":["scenario"],"path":"scenarios/progression-personalized-recommendations.json","sha256":"8bb96bf7c8a81df356cc0e4bd248184dc13924d78bfe85bf173f840899350e1d"},{"kinds":["scenario"],"path":"scenarios/progression-price-cart-checkout.json","sha256":"0e0f6383af25fa70701c7cc99a4b934da2318a68d168ea897333c8be943c8274"},{"kinds":["scenario"],"path":"scenarios/progression-product-bundles.json","sha256":"7d517f3c1265dae451ed4b0ed0f97186b340717561a10f030edd622f5a50163c"},{"kinds":["scenario"],"path":"scenarios/progression-promotion-checkout.json","sha256":"3e6baa221f1ab203893a2a105c809a3f221d985251a64f115d47e2ab58c180ec"},{"kinds":["scenario"],"path":"scenarios/progression-promotion-reporting.json","sha256":"8c9efe46cdeee1d1dd8d802a222bd1f58b06e997dc53a44fd8e19ff45586673e"},{"kinds":["scenario"],"path":"scenarios/progression-promotion-rules.json","sha256":"e49ea26a881a6d49c485a63d7f1f5cca55fb314522d9d948ed5c2f7eb2a84306"},{"kinds":["scenario"],"path":"scenarios/progression-purchasing.json","sha256":"b2aff32949f55c4819bde7b670c00896aacdbfe59f478fa46df9423da455bd12"},{"kinds":["scenario"],"path":"scenarios/progression-recommendation-feedback.json","sha256":"6a6bae970c29cd443a9e6c66919c909a9f0792a8c37a7d00d2c63f5e4be872c3"},{"kinds":["scenario"],"path":"scenarios/progression-review-access.json","sha256":"7b927506d22d2074af625aaf43e27649e4fc5ec7e5317e04c04dac323661d0cf"},{"kinds":["scenario"],"path":"scenarios/progression-review-script.json","sha256":"267a9134ddb8cd25d3e9d76b5595e97debd2a8071f8ff8e568aa7285b608d30f"},{"kinds":["scenario"],"path":"scenarios/progression-search-ordering.json","sha256":"b96f50c9ec28d68aa1fe4e6d6ea7631f6399f439025c6fe74c1d9a3ce8a55803"},{"kinds":["scenario"],"path":"scenarios/progression-shipping-accounting.json","sha256":"2e310fb4489c154617660b3d247136646c04faa903e958cf2561e9072615b779"},{"kinds":["scenario"],"path":"scenarios/progression-signed-out-purchase.json","sha256":"59de2a84876ae4542d783dca533764eb4f06bc390a67a37b25f0967477ee44fe"},{"kinds":["scenario"],"path":"scenarios/progression-split-tender-refunds.json","sha256":"39771047c0b0a84a6de5c4178e387c95581667cba5741e24d7a3555bc6a19018"},{"kinds":["scenario"],"path":"scenarios/progression-staff-access.json","sha256":"67de6a963d3cdb33dfb119ffacfdd1024d7f9c4d095bf90d553ef1c6efe235c9"},{"kinds":["scenario"],"path":"scenarios/progression-staff-activity.json","sha256":"28600137357ce5620f9f4919b25eb1ff27ba5aff4ed02285349e4d82cd1585a4"},{"kinds":["scenario"],"path":"scenarios/progression-staff-roles.json","sha256":"d87a2f7f0890a84614f538d7656de92082ba1c5843a40d3b2cf0f7f2d9097e11"},{"kinds":["scenario"],"path":"scenarios/progression-stock-alert-delivery.json","sha256":"e4899fb49e87edd9787997e9abb173c890604397fe096186ea0f601fd2e2f67f"},{"kinds":["scenario"],"path":"scenarios/progression-stock-alerts.json","sha256":"582bcb0bea4f109da56e761ad27c809cfb2da38edec41a9e4a528ea603c020f1"},{"kinds":["scenario"],"path":"scenarios/progression-stock-limit.json","sha256":"e07cd6c2b949b392cbb10f0f7cf8b2e8b74a0ef2ed17d563187ad28387eebc4a"},{"kinds":["scenario"],"path":"scenarios/progression-store-credit.json","sha256":"04a1fc19d215155c90a5382e91e15cbf01b400d6b2f8600b5a0e25b42132c820"},{"kinds":["scenario"],"path":"scenarios/progression-subscriptions.json","sha256":"de31264cfc1890ab6c3ebaead98c41964da70d135d34a5f4944ac41108998e94"},{"kinds":["scenario"],"path":"scenarios/progression-support-history.json","sha256":"86928df21aa68fec5c20993ec13e3b1c57291f38a35167996a99ef34f363a2b7"},{"kinds":["scenario"],"path":"scenarios/progression-support-intake.json","sha256":"c8d01303a3316f28de956fb2a72ab289905a46f5d689fe40b8193e12cea1753a"},{"kinds":["scenario"],"path":"scenarios/progression-support-refunds-access.json","sha256":"52f03c8a7ab8b1c7554f7d637bd5d46a19e24f4be5666eac14398ed1f1b2707b"},{"kinds":["scenario"],"path":"scenarios/progression-support-refunds-accounting.json","sha256":"38be5988391c96acfa7eac25248df674e0fe95e2b58f22ea47fa909a02f01576"},{"kinds":["scenario"],"path":"scenarios/progression-support-refunds-resolution.json","sha256":"2627a122fd791ed4ed2c4c08e7fea283e017bfe59dd1a682899207cc89d7ee67"},{"kinds":["scenario"],"path":"scenarios/progression-support-return-interaction.json","sha256":"7c50a90555a616e9e8ce7fefb771e79237ed2890b28545a5951da2fa52902820"},{"kinds":["scenario"],"path":"scenarios/progression-support-triage.json","sha256":"a0ad2546ae46257154a75fa3250353cd443f1c6dc93ff52b4e666e99444101f5"},{"kinds":["track-manifest"],"path":"track.json","sha256":"ae917ab791cfc59a6ece01cc23ab433a235cc5fb20ab37974d8ed36c494a67d9"}],"sourceManifestSha256":"82b2d124ed616d2690d1b8ae082cb1b6e3903cda31500662b334b4fd8cecf49f","task":{"baseRecipe":null,"composedSha256":"d063ef87268f9c5a4bb2e7c0f4570cd2ac6b50e9f45e1ca1c1df76049731f650","contractSha256":"e432e08fc81f67f95f38c44e05fc2adc393f10cd29d67af78d0f1676e73b7578","contracts":[{"from":null,"id":"ecommerce.application-interface","modes":["fresh","upgrade"],"order":0,"owners":["recipe"],"path":"contracts/application-interface.md","sha256":"b770db6c1dbf92c106c7501a17028876a30a63655c8f88b5667b44557f401692","until":null},{"from":null,"id":"ecommerce.progression.staff-access-hooks","modes":["fresh","upgrade"],"order":1900,"owners":["ecommerce.progression.staff-access"],"path":"contracts/staff-access.md","sha256":"dcd7b740d5f65160ddf0b4221d29f84426ee89f04560e953add0856cf0bca87a","until":null},{"from":null,"id":"ecommerce.progression.customer-profile-hooks","modes":["upgrade"],"order":1950,"owners":["ecommerce.progression.customer-profile"],"path":"contracts/customer-profile.md","sha256":"7451bf14ada950c9b7ad269d63467154c388e9ea18b97f479037cdd397ca519f","until":null},{"from":null,"id":"ecommerce.progression.staff-role-hooks","modes":["upgrade"],"order":1960,"owners":["ecommerce.progression.staff-roles"],"path":"contracts/staff-roles.md","sha256":"cce6145182485fafcd2adc29cec90af20523a2afd9c952800eefb5d15a49f96e","until":null},{"from":null,"id":"ecommerce.progression.catalog-management-hooks","modes":["upgrade"],"order":1970,"owners":["ecommerce.progression.catalog-management"],"path":"contracts/catalog-management.md","sha256":"5123971185ded331deaef2e323fad31e6133d55fc839289e2c4a0dfc5292ee4e","until":null},{"from":null,"id":"ecommerce.progression.payment-record-hooks","modes":["upgrade"],"order":1980,"owners":["ecommerce.progression.payment-records"],"path":"contracts/payment-records.md","sha256":"8c752352c7f47a0a65d1823f9ec74009dc95088fc6c2a6cc30d1a1dc7fa11fe0","until":null},{"from":null,"id":"ecommerce.progression.staff-activity-hooks","modes":["upgrade"],"order":1990,"owners":["ecommerce.progression.staff-activity"],"path":"contracts/staff-activity.md","sha256":"7e7c1846445f82aa78ad8e32606e6830f9d326ebfea75d13b077c073695c9594","until":null},{"from":null,"id":"ecommerce.feature.catalog-items.hooks","modes":["fresh","upgrade"],"order":2000,"owners":["ecommerce.feature.catalog-items"],"path":"contracts/catalog-items.md","sha256":"596ec08b1f4a6b290595570f3bcf2847a1f60feeb20d90f98d25761666bfe9f2","until":null},{"from":null,"id":"ecommerce.feature.catalog-discovery.hooks","modes":["fresh","upgrade"],"order":2010,"owners":["ecommerce.feature.catalog-discovery"],"path":"contracts/catalog-discovery.md","sha256":"d13ea495f78e3827b7a243b97466aefbf0252980c76edb432b6b0506854e8450","until":null},{"from":null,"id":"ecommerce.l2.transfer-hooks","modes":["upgrade"],"order":2031,"owners":["ecommerce.l2.stock-transfers-features"],"path":"contracts/stock-transfers.md","sha256":"01f28ebb3487559d4689919f0991e43f74fcc85609fa4c810e92adde30e84096","until":null},{"from":null,"id":"ecommerce.l2.price-hooks","modes":["upgrade"],"order":2041,"owners":["ecommerce.l2.price-history-features"],"path":"contracts/price-history.md","sha256":"3465714f91e0e978607900b19377a134e9beb704848e2462b1438465cc2e98ee","until":null},{"from":"# Price history completed-order interface","id":"ecommerce.progression.price-history-order-hooks","modes":["upgrade"],"order":2042,"owners":["ecommerce.progression.price-history-specifications"],"path":"contracts/price-history-orders.md","requiresFeatures":["ecommerce.feature.purchasing","ecommerce.l2.price-history-features"],"sha256":"45d360052ede67e50e12b5c0e64904dbbdd1dd17a430c38130a2b8a70d274278","until":"# Price history cart and checkout interface"},{"from":"# Price history cart and checkout interface","id":"ecommerce.progression.price-history-cart-hooks","modes":["upgrade"],"order":2043,"owners":["ecommerce.progression.price-history-specifications"],"path":"contracts/price-history-orders.md","requiresFeatures":["ecommerce.feature.checkout","ecommerce.l2.price-history-features"],"sha256":"0d80d8f3bb9ced280a6203d2e8974b1a4db923b2d423205969ca1d44d002fc8b","until":null},{"from":null,"id":"ecommerce.l2.inventory-dashboard-hooks","modes":["upgrade"],"order":2050,"owners":["ecommerce.l2.inventory-dashboard"],"path":"contracts/inventory-dashboard.md","sha256":"8c3de4ff8a958776ca087febbbbf5f950eaef9efacb96b7c4fa49357b2d0a371","until":null},{"from":null,"id":"ecommerce.l2.order-cancellation-hooks","modes":["upgrade"],"order":2060,"owners":["ecommerce.l2.order-cancellation-features"],"path":"contracts/order-cancellation.md","sha256":"fc274b1409c50de8edcf797ab83cf8e8c46a54db30ada859f854e1cd40c7dee1","until":null},{"from":null,"id":"ecommerce.l2.sales-dashboard-hooks","modes":["upgrade"],"order":2060,"owners":["ecommerce.l2.sales-dashboard"],"path":"contracts/sales-dashboard.md","sha256":"ff9ed3890aa5c8303a0badecf946e7d98da3fbbb0a2890a693099bab1a2056c0","until":null},{"from":null,"id":"ecommerce.l2.recommendations-hooks","modes":["upgrade"],"order":2070,"owners":["ecommerce.l2.recommendations"],"path":"contracts/recommendations.md","sha256":"ab5417cbf78f43464e82a543e50e9601580bb2b3a57826a9e73da9899f39de16","until":null},{"from":null,"id":"ecommerce.feature.accounts.hooks","modes":["fresh","upgrade"],"order":2100,"owners":["ecommerce.feature.accounts"],"path":"contracts/accounts.md","sha256":"e281aa0cff56c23117203b13d11f6787a7f8163cb8d1b7bc0d2d86b5390cfff6","until":null},{"from":null,"id":"ecommerce.feature.purchasing.hooks","modes":["fresh","upgrade"],"order":2200,"owners":["ecommerce.feature.purchasing"],"path":"contracts/purchasing.md","sha256":"c2d59da67b400d055ab90bf53f2e46a3af9605a1fc68534c2b64d8db2ed3409c","until":null},{"from":null,"id":"ecommerce.feature.cart.hooks","modes":["fresh","upgrade"],"order":2300,"owners":["ecommerce.feature.cart"],"path":"contracts/cart.md","sha256":"bb1b8741b9eb47b5766a330bb1fc23005f7540fdc79d20efdaefb183cf50918d","until":null},{"from":null,"id":"ecommerce.feature.checkout.hooks","modes":["fresh","upgrade"],"order":2310,"owners":["ecommerce.feature.checkout"],"path":"contracts/checkout.md","sha256":"49416683e06d996a28980ff650a3281f89cae062269b7de761899e71759c731c","until":null},{"from":null,"id":"ecommerce.orders.data","modes":["fresh","upgrade"],"order":2315,"owners":["ecommerce.feature.checkout","ecommerce.feature.purchasing"],"path":"contracts/order-data.md","sha256":"7b7cfc6b102f4836235c7f23344865f60156b3e4ac96c3e5cbb0e298390b3b06","until":null},{"from":null,"id":"ecommerce.feature.reviews.hooks","modes":["fresh","upgrade"],"order":2400,"owners":["ecommerce.feature.reviews"],"path":"contracts/reviews.md","sha256":"6be3567258c0c4bf3331e609f63be26ad0bb43ceca3e7da4accaaad8c9ac6541","until":null},{"from":null,"id":"ecommerce.feature.warehouse-admin.hooks","modes":["fresh","upgrade"],"order":2500,"owners":["ecommerce.feature.warehouse-admin"],"path":"contracts/warehouse-administration.md","sha256":"ea037935ce439d10f4ccea3296bb16aa2ddee4e0c13b2b7ade0638ff7cb9b8d6","until":null},{"from":null,"id":"ecommerce.progression.support-history-hooks","modes":["upgrade"],"order":2900,"owners":["ecommerce.progression.support-history"],"path":"contracts/support-history.md","sha256":"610022f964c2aa00b409fb2723f91b885e306edde5bf73390e880cffd2a5583d","until":null},{"from":null,"id":"ecommerce.progression.support-intake-hooks","modes":["fresh","upgrade"],"order":2900,"owners":["ecommerce.progression.support-intake"],"path":"contracts/support-intake.md","sha256":"fd9f732acf67d6c772f4c05d626e4e9e472818fc5226b7ef3d7223b85a0e0bc7","until":null},{"from":null,"id":"ecommerce.progression.support-triage-hooks","modes":["upgrade"],"order":2900,"owners":["ecommerce.progression.support-triage"],"path":"contracts/support-triage.md","sha256":"8079080a299674bb0558a6550243051360be1c0f18252708128c3f71af899a0d","until":null},{"from":null,"id":"ecommerce.progression.fulfilment-queue-hooks","modes":["upgrade"],"order":2920,"owners":["ecommerce.progression.fulfilment-queue"],"path":"contracts/operations-access.md","sha256":"fd9c31482b484dc1f9bf3c521d247971334e1f52f51a7548a987bdebc65dbdb5","until":null},{"from":null,"id":"ecommerce.progression.promotion-rules-hooks","modes":["upgrade"],"order":2950,"owners":["ecommerce.progression.promotion-rules"],"path":"contracts/promotion-rules.md","sha256":"f352f8bb938aa874125b10bbb6182643f04b6d1ce82cde41512bd16835a7b90b","until":null},{"from":null,"id":"ecommerce.progression.notification-preferences-hooks","modes":["upgrade"],"order":2990,"owners":["ecommerce.progression.notification-preferences"],"path":"contracts/notification-preferences.md","sha256":"d6b4231f67d5e70a03ec331545b6419acf766b52841c8520b94963c16aa13fec","until":null},{"from":null,"id":"ecommerce.l3.reservation-hooks","modes":["upgrade"],"order":3900,"owners":["ecommerce.l3.reservations-features"],"path":"contracts/reservations.md","sha256":"e1c4af7a67dd200d5f18d550e5b4c30e7a4bbaf60600b434108ebff7bdf90627","until":null},{"from":null,"id":"ecommerce.progression.managed-support-hooks","modes":["upgrade"],"order":3900,"owners":["ecommerce.progression.managed-support"],"path":"contracts/managed-support.md","sha256":"458b89a7f786086a95957c778943660068cd6c00b30635fd1cd786c37df76398","until":null},{"from":null,"id":"ecommerce.l3.scheduled-restock-hooks","modes":["upgrade"],"order":3910,"owners":["ecommerce.l3.scheduled-restocks-features"],"path":"contracts/scheduled-restocks.md","sha256":"a946c0954a641d4fe64b933761e2b92d546ae08ee434d676c6faed3ed8b03c8e","until":null},{"from":null,"id":"ecommerce.l3.order-delivery-hooks","modes":["upgrade"],"order":3920,"owners":["ecommerce.l3.order-delivery-features"],"path":"contracts/order-delivery.md","sha256":"74bd21b39c8d5f020ff62cc408992c15788e48eba8e05a76a0cddc4b4920a98e","until":null},{"from":null,"id":"ecommerce.l3.cart-expiration-hooks","modes":["upgrade"],"order":3930,"owners":["ecommerce.l3.cart-expiration-features"],"path":"contracts/cart-expiration.md","sha256":"56c0966494cd19b629140f8b8d53e8b9838e34668a5cab6b7cccb41b78734c50","until":null},{"from":null,"id":"ecommerce.progression.promotion-checkout-hooks","modes":["upgrade"],"order":3950,"owners":["ecommerce.progression.promotion-checkout"],"path":"contracts/promotion-checkout.md","sha256":"b74e703dc77c9eeec26f5beb41cab102570c8314d817015c858557e9946293aa","until":null},{"from":null,"id":"ecommerce.progression.stock-alert-hooks","modes":["upgrade"],"order":3990,"owners":["ecommerce.progression.stock-alerts"],"path":"contracts/stock-alerts.md","sha256":"405f106569c84b3062f8159452730f16adadf12d804c554a570e39b958b63421","until":null},{"from":null,"id":"ecommerce.l3.order-return-hooks","modes":["upgrade"],"order":4041,"owners":["ecommerce.l3.order-returns-features"],"path":"contracts/order-returns.md","sha256":"fe0668ab3bf00d4c167794dbecb75b26b23cb62dfc0a1b79636a013edb237329","until":null},{"from":null,"id":"ecommerce.progression.faceted-search-hooks","modes":["upgrade"],"order":4900,"owners":["ecommerce.progression.faceted-search"],"path":"contracts/faceted-search.md","sha256":"08ace4d2d1947f16ceb4da95e6993086c9bd77a0977c258fef1f0a96c7e7879d","until":null},{"from":null,"id":"ecommerce.progression.order-support-hooks","modes":["upgrade"],"order":4900,"owners":["ecommerce.progression.order-support"],"path":"contracts/order-support.md","sha256":"a2901e66af870055b6c3c26f240132ae08f3cb93d0c52a7b2573c9dc153e1e03","until":null},{"from":null,"id":"ecommerce.progression.personalized-recommendation-hooks","modes":["upgrade"],"order":4910,"owners":["ecommerce.progression.personalized-recommendations"],"path":"contracts/progression-personalized-recommendations.md","sha256":"42389a6d284dcfdb53a610ce5ce77d40dbc2b9d5e177bbd3f6bccc40079c7d98","until":null},{"from":null,"id":"ecommerce.progression.promotion-reporting-hooks","modes":["upgrade"],"order":4950,"owners":["ecommerce.progression.promotion-reporting"],"path":"contracts/promotion-reporting.md","sha256":"81cded5fd9a8822c8756ea50bedb879971c94f8727d176f22fa53d2a6a1efbb0","until":null},{"from":null,"id":"ecommerce.feature.store-credit.interface","modes":["upgrade"],"order":5900,"owners":["ecommerce.feature.store-credit"],"path":"contracts/store-credit.md","sha256":"505ca48dfc4f9f2d6ea38e53e1bd382910264d0195be8580b5fb01f7e7074713","until":null},{"from":null,"id":"ecommerce.feature.subscriptions.interface","modes":["upgrade"],"order":5900,"owners":["ecommerce.feature.subscriptions"],"path":"contracts/subscriptions.md","sha256":"dc533bc7f3b9be03ae7d9e18c2e02ffa996bf934b9ba230826d492b4cefa045e","until":null},{"from":null,"id":"ecommerce.progression.delivery-notification-hooks","modes":["upgrade"],"order":5900,"owners":["ecommerce.progression.delivery-notifications"],"path":"contracts/delivery-notifications.md","sha256":"4bf565ea751bb5278bae5910420beeb531a2eb88fb5755e5a06dda68860af490","until":null},{"from":null,"id":"ecommerce.progression.support-refund-hooks","modes":["upgrade"],"order":5900,"owners":["ecommerce.progression.support-refunds"],"path":"contracts/support-refunds.md","sha256":"da5d0e69bbf3a028dc79f207b940bbd4a79e7f82c68d89f252eb8c73ea16b8bc","until":null},{"from":null,"id":"ecommerce.progression.automatic-reorder-hooks","modes":["upgrade"],"order":5910,"owners":["ecommerce.progression.automatic-reorder"],"path":"contracts/progression-automatic-reorder.md","sha256":"3e70361965e6ddeb7b05cc7ad5348e363d58d628734de96b8a9792e68e71cc72","until":null},{"from":null,"id":"ecommerce.progression.cart-recovery-hooks","modes":["upgrade"],"order":5920,"owners":["ecommerce.progression.cart-recovery"],"path":"contracts/progression-cart-recovery.md","sha256":"daf04aea3082483caa2ebf3a3c89a438329600cb6aa5d74fb47d97bc244e5747","until":null},{"from":null,"id":"ecommerce.progression.recommendation-feedback-hooks","modes":["upgrade"],"order":5930,"owners":["ecommerce.progression.recommendation-feedback"],"path":"contracts/recommendation-feedback.md","sha256":"00a96f594c8da1ffb4a933c6f8d8d0219216ab6cc2c781cfd17dd9c97c517d58","until":null},{"from":null,"id":"ecommerce.feature.split-tender-refunds.interface","modes":["upgrade"],"order":6900,"owners":["ecommerce.feature.split-tender-refunds"],"path":"contracts/split-tender-refunds.md","sha256":"62b8b3c233d33858e9b696d06d94c70f6524f8cbed77028acc0d2affdd780841","until":null},{"from":null,"id":"ecommerce.interface.product-bundles","modes":["upgrade"],"order":8104,"owners":["ecommerce.feature.product-bundles"],"path":"contracts/product-bundles.md","sha256":"b27905002b693e6c63532cd8193c8e3fd1fdeaad85041d84b8240a2092bf1c57","until":null},{"from":null,"id":"ecommerce.interface.bundle-checkout","modes":["upgrade"],"order":8105,"owners":["ecommerce.feature.bundle-checkout"],"path":"contracts/bundle-checkout.md","sha256":"2c4e70b620934dc927ad4c84c17e54b6e9cef665ba3b098f9f2fc9e79a3c4c3e","until":null},{"from":null,"id":"ecommerce.interface.bundle-returns","modes":["upgrade"],"order":8106,"owners":["ecommerce.feature.bundle-returns"],"path":"contracts/bundle-returns.md","sha256":"69f8bf6afc325a98bab38235e49eaa2875bc674e6a61c7559692593018c9f527","until":null}],"mode":"action","requirementSha256":"bd057cbfbcae06db5bdd6a7eb20d03ae00f9c16cff9841199b342a7df5b19279","requirements":[{"from":null,"id":"ecommerce.progression.fresh","modes":["fresh"],"order":0,"owners":["recipe"],"path":"prompts/modular/progression-framing.md","sha256":"7c3267ef4ef6a454ba26217d8a0efc47f1cbe655970fbb1ddfd2ae7637e17df1","until":"## Existing application"},{"from":"## Existing application","id":"ecommerce.progression.upgrade","modes":["upgrade"],"order":0,"owners":["recipe"],"path":"prompts/modular/progression-framing.md","sha256":"ad2dc327dea4410a715b013d9455c37060a193b844c7de7967ce760ef1c2c118","until":null},{"from":null,"id":"ecommerce.l2.inventory-dashboard","modes":["upgrade"],"order":50,"owners":["ecommerce.l2.inventory-dashboard"],"path":"prompts/modular/inventory-dashboard.md","sha256":"d2190c809ce459141cfdb716d25d38b01f7aca2ce8b8f74128e731e4e3fede07","until":null},{"from":null,"id":"ecommerce.l2.sales-dashboard","modes":["upgrade"],"order":60,"owners":["ecommerce.l2.sales-dashboard"],"path":"prompts/modular/sales-dashboard.md","sha256":"c65aaadb1f8da6e2b5f7967cc3bcf07beb0e7a860351e866373667bc33012dbd","until":null},{"from":null,"id":"ecommerce.l2.recommendations","modes":["upgrade"],"order":70,"owners":["ecommerce.l2.recommendations"],"path":"prompts/modular/recommendations.md","sha256":"0eed3feb6fc6acf86260d74eeff557b15837aaa09a857c63cf9dee848cd7201f","until":null},{"from":null,"id":"ecommerce.feature.accounts.requirement","modes":["fresh","upgrade"],"order":100,"owners":["ecommerce.feature.accounts"],"path":"prompts/modular/accounts.md","sha256":"0a8dee0847a02da7777c11c4175577c4533fafa538fc09e5124cf4d825e4c96f","until":null},{"from":null,"id":"ecommerce.feature.catalog-items.requirement","modes":["fresh","upgrade"],"order":200,"owners":["ecommerce.feature.catalog-items"],"path":"prompts/modular/catalog-items.md","sha256":"36a72da77f42d856b691c93dc587fee6d9d7f88b722a9893fc226b1d5bb5d3fe","until":null},{"from":null,"id":"ecommerce.feature.catalog-discovery.requirement","modes":["fresh","upgrade"],"order":210,"owners":["ecommerce.feature.catalog-discovery"],"path":"prompts/modular/catalog-discovery.md","sha256":"9a0785c55d17e577b84ef257de482bcd8bc8c961e9d0760c38472936a1a0062b","until":null},{"from":null,"id":"ecommerce.feature.purchasing.requirement","modes":["fresh","upgrade"],"order":300,"owners":["ecommerce.feature.purchasing"],"path":"prompts/modular/purchasing.md","sha256":"059073391cf92eef2fb1edb710ec1a62747e82115c2bd0251274111b92f93e46","until":null},{"from":null,"id":"ecommerce.feature.cart.requirement","modes":["fresh","upgrade"],"order":400,"owners":["ecommerce.feature.cart"],"path":"prompts/modular/cart.md","sha256":"da024de4032661a46574c8ac8dbe3d1baf45ef6ea7115ba1976d7d5c1044afbe","until":null},{"from":null,"id":"ecommerce.feature.checkout.requirement","modes":["fresh","upgrade"],"order":410,"owners":["ecommerce.feature.checkout"],"path":"prompts/modular/checkout.md","sha256":"bb834dec7858349a17a8980eb13459a606cdbd2b1c534f468f666459c1a24ba7","until":null},{"from":null,"id":"ecommerce.feature.reviews.requirement","modes":["fresh","upgrade"],"order":500,"owners":["ecommerce.feature.reviews"],"path":"prompts/modular/reviews.md","sha256":"1649822528e1bbcfedc59b3c8c5d7ff1b5f0e42e1e82b81ee7e59361cbefab33","until":null},{"from":null,"id":"ecommerce.feature.warehouse-admin.requirement","modes":["fresh","upgrade"],"order":600,"owners":["ecommerce.feature.warehouse-admin"],"path":"prompts/modular/warehouse-administration.md","sha256":"8fa2d7b54b3c3d9601ae69bbfee5bdf389f68fea0d0ef4032201af12d3f424a2","until":null},{"from":"## Access control: purchasing","id":"ecommerce.spec.access-control.purchasing","modes":["fresh"],"order":1000,"owners":["ecommerce.spec.access-control"],"path":"prompts/modular/l1-specifications.md","requiresFeatures":["ecommerce.feature.purchasing"],"sha256":"45c2ac9e423af1431c6a9d8b7de707b7d6a8402c004c5472c56d7efe387e61a1","until":"## Access control: warehouse administration"},{"from":"## Access control: warehouse administration","id":"ecommerce.spec.access-control.warehouse-admin","modes":["fresh"],"order":1010,"owners":["ecommerce.spec.access-control"],"path":"prompts/modular/l1-specifications.md","requiresFeatures":["ecommerce.feature.warehouse-admin"],"sha256":"02500e3bded8076287f0b4c7264fe48ff3c766b0ab9aa386497c5cc66fc725f4","until":"## Access control: reviews"},{"from":"## Access control: reviews","id":"ecommerce.spec.access-control.reviews","modes":["fresh"],"order":1020,"owners":["ecommerce.spec.access-control"],"path":"prompts/modular/l1-specifications.md","requiresFeatures":["ecommerce.feature.reviews"],"sha256":"10d4140e8f649ddf46843100231683f13143c09226195cfe487827b662333f4d","until":"## Access control: cart"},{"from":"## Access control: cart","id":"ecommerce.spec.access-control.cart","modes":["fresh"],"order":1030,"owners":["ecommerce.spec.access-control"],"path":"prompts/modular/l1-specifications.md","requiresFeatures":["ecommerce.feature.cart"],"sha256":"353e3d5daa87c988456b392ad53fd93bdf473b5a860049104cd5acdaddf05cee","until":"## State durability: accounts"},{"from":null,"id":"ecommerce.progression.staff-access","modes":["fresh","upgrade"],"order":1100,"owners":["ecommerce.progression.staff-access"],"path":"prompts/modular/staff-access.md","sha256":"10c6aedbc5c60b440d6d0b5c38bb57363ae021c54d62ee2ffe2294d7f6741550","until":null},{"from":"## State durability: accounts","id":"ecommerce.spec.state-durability.accounts","modes":["fresh"],"order":1100,"owners":["ecommerce.spec.state-durability"],"path":"prompts/modular/l1-specifications.md","requiresFeatures":["ecommerce.feature.accounts"],"sha256":"3466c8854dd16c38beafe194fb402f8f5c5539defb90a9b856c357347255c3ee","until":"## State durability: account data"},{"from":"## State durability: account data","id":"ecommerce.spec.state-durability.account-data","modes":["fresh"],"order":1110,"owners":["ecommerce.spec.state-durability"],"path":"prompts/modular/l1-specifications.md","requiresFeatures":["ecommerce.feature.accounts","ecommerce.feature.cart"],"sha256":"db7e1e0fbf6e6f2956f28ef00dfc7191c90ca05349a605f246776ff3c6f4e2d9","until":"## Live state: catalog and purchasing"},{"from":null,"id":"ecommerce.spec.state-durability.checkout-crash","modes":["fresh","upgrade"],"order":1120,"owners":["ecommerce.spec.state-durability"],"path":"prompts/modular/checkout-recovery-specification.md","requiresFeatures":["ecommerce.feature.checkout"],"sha256":"0e851fea800d81cb558f8004f04e628e5ccf9f6e5589a9d2f6fceaf33e50f207","until":null},{"from":null,"id":"ecommerce.progression.customer-profile","modes":["upgrade"],"order":1200,"owners":["ecommerce.progression.customer-profile"],"path":"prompts/modular/customer-profile.md","sha256":"f4ffc5d2a642bbccec9eb5c428a37b2d9bfaa1c9f96648d8544bfcf2fe8187bb","until":null},{"from":null,"id":"ecommerce.progression.support-intake","modes":["fresh","upgrade"],"order":1200,"owners":["ecommerce.progression.support-intake"],"path":"prompts/modular/support-intake.md","sha256":"048f11b71b66dadf80c77b5d9aef8bbff2b2030171eeda5012dce74ae16421ed","until":null},{"from":"## Live state: catalog and purchasing","id":"ecommerce.spec.live-state.catalog-purchasing","modes":["fresh"],"order":1200,"owners":["ecommerce.spec.live-state"],"path":"prompts/modular/l1-specifications.md","requiresFeatures":["ecommerce.feature.catalog-items","ecommerce.feature.purchasing"],"sha256":"3bfd8cf26509ffeeb475df0eee040f4743cc31acd9e8292e4144b46055686b55","until":"## Live state: cart"},{"from":"## Live state: cart","id":"ecommerce.spec.live-state.cart","modes":["fresh"],"order":1210,"owners":["ecommerce.spec.live-state"],"path":"prompts/modular/l1-specifications.md","requiresFeatures":["ecommerce.feature.cart"],"sha256":"244ee5cf7387c74dd1776e659964e782f042229eff84918de2517781ad095045","until":"## Live state: reviews"},{"from":"## Live state: reviews","id":"ecommerce.spec.live-state.reviews","modes":["fresh"],"order":1220,"owners":["ecommerce.spec.live-state"],"path":"prompts/modular/l1-specifications.md","requiresFeatures":["ecommerce.feature.reviews"],"sha256":"aeeab5a0dda0f1df6b1ab3ae78d3c1c6a9ff2f108ac1d09e904c27b7ee71100d","until":"## Live state: warehouse administration"},{"from":"## Live state: warehouse administration","id":"ecommerce.spec.live-state.warehouse-admin","modes":["fresh"],"order":1230,"owners":["ecommerce.spec.live-state"],"path":"prompts/modular/l1-specifications.md","requiresFeatures":["ecommerce.feature.catalog-items","ecommerce.feature.warehouse-admin"],"sha256":"362d4ef3422a09d060cdd5b09837b0a4a1f67b8fb108f59dcf7afb4a12d2a4e5","until":"## Concurrency safety: purchasing"},{"from":null,"id":"ecommerce.progression.staff-roles","modes":["upgrade"],"order":1250,"owners":["ecommerce.progression.staff-roles"],"path":"prompts/modular/staff-roles.md","sha256":"175a323c92238509111aa9c366e4ec302d508edc872077ecd26d8acbcbe21ba9","until":null},{"from":null,"id":"ecommerce.progression.catalog-management","modes":["upgrade"],"order":1300,"owners":["ecommerce.progression.catalog-management"],"path":"prompts/modular/catalog-management.md","sha256":"93fece29e1d68513732398c815fe4ebc83079e705e2b9de40df543281439f390","until":null},{"from":"## Concurrency safety: purchasing","id":"ecommerce.spec.concurrency-safety.purchasing","modes":["fresh"],"order":1300,"owners":["ecommerce.spec.concurrency-safety"],"path":"prompts/modular/l1-specifications.md","requiresFeatures":["ecommerce.feature.purchasing"],"sha256":"e2995c00f9971e1389bc03b56faf4e03da9c83a84cb205ddfeb84964bd4a905f","until":"## Concurrency safety: restocking"},{"from":"## Concurrency safety: restocking","id":"ecommerce.spec.concurrency-safety.restocking","modes":["fresh"],"order":1310,"owners":["ecommerce.spec.concurrency-safety"],"path":"prompts/modular/l1-specifications.md","requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.warehouse-admin"],"sha256":"958e12514579d21f92a73806ba6983912f1828f40f51efeb16947e7a6c3d539e","until":"## Concurrency safety: checkout"},{"from":"## Concurrency safety: checkout","id":"ecommerce.spec.concurrency-safety.checkout","modes":["fresh"],"order":1320,"owners":["ecommerce.spec.concurrency-safety"],"path":"prompts/modular/l1-specifications.md","requiresFeatures":["ecommerce.feature.checkout"],"sha256":"0bb644068b430d491cfd6c6f5af00cf16cff7ec930a1d8b3150493e4d0bebbe5","until":"## Transactional integrity: reviews"},{"from":null,"id":"ecommerce.progression.payment-records","modes":["upgrade"],"order":1350,"owners":["ecommerce.progression.payment-records"],"path":"prompts/modular/payment-records.md","sha256":"ab5c9c913041e324cad82fe6a135d78906818afa3c9a5c204289142c1d696f09","until":null},{"from":null,"id":"ecommerce.progression.staff-activity","modes":["upgrade"],"order":1400,"owners":["ecommerce.progression.staff-activity"],"path":"prompts/modular/staff-activity.md","sha256":"0cb274acefc0d75cd82415de0eb167133db0412e1de4f0fd59f62983d29a1476","until":null},{"from":"## Transactional integrity: reviews","id":"ecommerce.spec.transactional-integrity.reviews","modes":["fresh"],"order":1400,"owners":["ecommerce.spec.transactional-integrity"],"path":"prompts/modular/l1-specifications.md","requiresFeatures":["ecommerce.feature.reviews"],"sha256":"715afabddf7a8ed221f38fdba2b89dad7d0b656c62f5e607153ef39ec52e2fc0","until":"## Transactional integrity: purchasing"},{"from":"## Transactional integrity: purchasing","id":"ecommerce.spec.transactional-integrity.purchasing","modes":["fresh"],"order":1410,"owners":["ecommerce.spec.transactional-integrity"],"path":"prompts/modular/l1-specifications.md","requiresFeatures":["ecommerce.feature.purchasing"],"sha256":"1452a3c92e5a35b5bed9273e146de8d1dda3011105ec5d79821462629ef56c8d","until":"## Transactional integrity: warehouse accounting"},{"from":"## Transactional integrity: warehouse accounting","id":"ecommerce.spec.transactional-integrity.warehouse-accounting","modes":["fresh"],"order":1420,"owners":["ecommerce.spec.transactional-integrity"],"path":"prompts/modular/l1-specifications.md","requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.warehouse-admin"],"sha256":"667b2197f1e9c20e22f03abc7cc756b98b421377adfdb3fd06f35005837c3948","until":"## External data synchronization"},{"from":"## External data synchronization","id":"ecommerce.spec.external-data-sync.requirement","modes":["fresh","upgrade"],"order":1500,"owners":["ecommerce.spec.external-data-sync"],"path":"prompts/modular/l1-external-sync-specifications.md","requiresFeatures":["ecommerce.feature.warehouse-admin"],"sha256":"0e3db28232aedb57b3fb2fbb9afa3ca65fcad28b8c050e1965feee4db32e4239","until":null},{"from":null,"id":"ecommerce.progression.fulfilment-queue","modes":["upgrade"],"order":2020,"owners":["ecommerce.progression.fulfilment-queue"],"path":"prompts/modular/operations-access.md","sha256":"1699a8d0466e115874e49b8ae73bb0004c3c620a03d3aa04dd83818b6c798003","until":null},{"from":null,"id":"ecommerce.l2.stock-transfer","modes":["upgrade"],"order":2030,"owners":["ecommerce.l2.stock-transfers-features"],"path":"prompts/modular/stock-transfers.md","sha256":"6e2f0735d81fd5376b851893404873af4807b83e807e078cca0b8c9a9920e627","until":null},{"from":null,"id":"ecommerce.l2.order-cancellation","modes":["upgrade"],"order":2040,"owners":["ecommerce.l2.order-cancellation-features"],"path":"prompts/modular/order-cancellation.md","sha256":"7d429d4e8db546961e7ec9a12fb5dcba5efd0562c8059ab354121fd5ed13ea84","until":null},{"from":null,"id":"ecommerce.l2.price-history","modes":["upgrade"],"order":2040,"owners":["ecommerce.l2.price-history-features"],"path":"prompts/modular/price-history.md","sha256":"9edb3db98af12f3a08cae7887dd6da91c746be49597f086457fc2ecb70c558b8","until":null},{"from":"## Price history: completed orders","id":"ecommerce.progression.price-history-orders","modes":["upgrade"],"order":2041,"owners":["ecommerce.progression.price-history-specifications"],"path":"prompts/modular/price-history-orders.md","requiresFeatures":["ecommerce.feature.purchasing","ecommerce.l2.price-history-features"],"sha256":"12abf44d08a49b076c721b62c4fc240a82c0fb350b10a3eb052afcf2ee78c6b6","until":"## Price history: cart and checkout"},{"from":"## Price history: cart and checkout","id":"ecommerce.progression.price-history-cart-checkout","modes":["upgrade"],"order":2042,"owners":["ecommerce.progression.price-history-specifications"],"path":"prompts/modular/price-history-orders.md","requiresFeatures":["ecommerce.feature.checkout","ecommerce.l2.price-history-features"],"sha256":"86caeac95b2d3cb1fc0ec0d467ee52303218d087ca30c24eb38c7c7714c8ec2b","until":null},{"from":null,"id":"ecommerce.progression.cancellation-queue","modes":["upgrade"],"order":2045,"owners":["ecommerce.progression.cancellation-queue-specifications"],"path":"prompts/modular/cancellation-queue.md","requiresFeatures":["ecommerce.l2.order-cancellation-features","ecommerce.progression.fulfilment-queue"],"sha256":"7e1adf98391a930017acb5c37d46c9b0d17d89e58c939fc57dc52f22e2f86f31","until":null},{"from":"## Cancellation accounting","id":"ecommerce.progression.cancellation-accounting","modes":["upgrade"],"order":2100,"owners":["ecommerce.progression.cancellation-accounting-specifications"],"path":"prompts/modular/order-accounting.md","requiresFeatures":["ecommerce.l2.order-cancellation-features"],"sha256":"a31e83bef57e79d545be549b9905d1b1f178e40a34e676ec18a62dfddf916d8d","until":"## Price accounting"},{"from":null,"id":"ecommerce.progression.support-triage","modes":["upgrade"],"order":2100,"owners":["ecommerce.progression.support-triage"],"path":"prompts/modular/support-triage.md","sha256":"bbb35abcbae9b8d3782ee3eb94f3175428edfe3fa564d6b0e3af2e0050e10dee","until":null},{"from":"## Price accounting","id":"ecommerce.progression.price-accounting","modes":["upgrade"],"order":2110,"owners":["ecommerce.progression.price-accounting-specifications"],"path":"prompts/modular/order-accounting.md","requiresFeatures":["ecommerce.l2.price-history-features"],"sha256":"64f96277738b0a33453e69bdcb1d79971d979a57ec27b8caacc96b499bc43de5","until":null},{"from":null,"id":"ecommerce.progression.support-history","modes":["upgrade"],"order":2110,"owners":["ecommerce.progression.support-history"],"path":"prompts/modular/support-history.md","sha256":"df2ca2664901a90814eab17d5f7c029595ef614d76ee29eeb4204d9f4f371429","until":null},{"from":null,"id":"ecommerce.progression.promotion-rules","modes":["upgrade"],"order":2200,"owners":["ecommerce.progression.promotion-rules"],"path":"prompts/modular/promotion-rules.md","sha256":"7a43b632e8fd43b8060100f9614476e41003e47afa04dd1b7c3b09639f6280b2","until":null},{"from":null,"id":"ecommerce.progression.notification-preferences","modes":["upgrade"],"order":2300,"owners":["ecommerce.progression.notification-preferences"],"path":"prompts/modular/notification-preferences.md","sha256":"496baa70ef300e6874f6dbf58ccd2bac594e53101875fd68740e27779d11871b","until":null},{"from":null,"id":"ecommerce.progression.transfer-authorization","modes":["upgrade"],"order":2930,"owners":["ecommerce.progression.operations-access-specifications"],"path":"prompts/modular/transfer-authorization.md","requiresFeatures":["ecommerce.l2.stock-transfers-features"],"sha256":"6d1e33c7a6aa209ad3f2705607a839dde5c915b65d78a8bb10b9e0da29172c0b","until":null},{"from":null,"id":"ecommerce.progression.price-authorization","modes":["upgrade"],"order":2940,"owners":["ecommerce.progression.operations-access-specifications"],"path":"prompts/modular/price-authorization.md","requiresFeatures":["ecommerce.l2.price-history-features"],"sha256":"6e9f949bd45f3bc816336de6e7db6dd18254ceebe6ecacc8e0abfd5f3887b8b5","until":null},{"from":null,"id":"ecommerce.progression.shipping-authorization","modes":["upgrade"],"order":2950,"owners":["ecommerce.progression.operations-access-specifications"],"path":"prompts/modular/shipping-authorization.md","requiresFeatures":["ecommerce.progression.fulfilment-queue"],"sha256":"f336e9c8e1ea425c3dc44e72fabbc5e9e0e2a3541cab3750dd8e112b6c7997f8","until":null},{"from":null,"id":"ecommerce.progression.order-ownership","modes":["upgrade"],"order":2960,"owners":["ecommerce.progression.operations-access-specifications"],"path":"prompts/modular/order-ownership.md","requiresFeatures":["ecommerce.l2.order-cancellation-features"],"sha256":"1f4e5149768d1d0a4917ca9b711f1f40bf2c783ee5d59a42ab307f01babb052e","until":null},{"from":null,"id":"ecommerce.progression.review-access","modes":["upgrade"],"order":2970,"owners":["ecommerce.progression.review-access-specifications"],"path":"prompts/modular/review-access.md","requiresFeatures":["ecommerce.feature.reviews"],"sha256":"430fe60b2f028f67eab9f23b572238d4dacc60f7b89d74f8030618368455f371","until":null},{"from":null,"id":"ecommerce.progression.transfer-conservation","modes":["upgrade"],"order":2970,"owners":["ecommerce.progression.inventory-conservation-specifications"],"path":"prompts/modular/stock-conservation.md","requiresFeatures":["ecommerce.l2.stock-transfers-features"],"sha256":"4551438e045bb65b44127d3f92dcb79548c78dc1ecc42d2c7807a599d6c59c8f","until":null},{"from":null,"id":"ecommerce.progression.cancellation-conservation","modes":["upgrade"],"order":2980,"owners":["ecommerce.progression.inventory-conservation-specifications"],"path":"prompts/modular/cancellation-conservation.md","requiresFeatures":["ecommerce.l2.order-cancellation-features"],"sha256":"f383c20f16d75b77dfe2c0ca10dc1c77c998feb80b7c327616512b486c4714f8","until":null},{"from":null,"id":"ecommerce.l3.reservations","modes":["upgrade"],"order":3000,"owners":["ecommerce.l3.reservations-features"],"path":"prompts/modular/reservations.md","sha256":"e45b53568066c7200486453f78fdbbe89a116259a4d83d9435bde350316595e0","until":null},{"from":null,"id":"ecommerce.l3.scheduled-restocks","modes":["upgrade"],"order":3010,"owners":["ecommerce.l3.scheduled-restocks-features"],"path":"prompts/modular/scheduled-restocks.md","sha256":"ba32547038c681f7214219e5a10df75dbf925ee19d4ba60db5b291570f9c16ec","until":null},{"from":null,"id":"ecommerce.l3.order-delivery","modes":["upgrade"],"order":3020,"owners":["ecommerce.l3.order-delivery-features"],"path":"prompts/modular/order-delivery.md","sha256":"40483d0bf91c81efe57a61d62dbda756498792383bed9af595cdd8878a0b0cb8","until":null},{"from":null,"id":"ecommerce.l3.cart-expiration","modes":["upgrade"],"order":3030,"owners":["ecommerce.l3.cart-expiration-features"],"path":"prompts/modular/cart-expiration.md","sha256":"7c66696f044249d5f7f31487efb85e83f4c06b862fbaa3dd142ef2aef6afc2b7","until":null},{"from":"## Durable reservations","id":"ecommerce.l3.durable-reservations","modes":["upgrade"],"order":3100,"owners":["ecommerce.l3.deferred-durability-specifications"],"path":"prompts/modular/l3-specifications.md","requiresFeatures":["ecommerce.l3.reservations-features"],"sha256":"18ec31e622e6d392c68eacef275c6595125aa9bc45296e6064be50353b228bc6","until":"## Durable restocks"},{"from":null,"id":"ecommerce.progression.managed-support","modes":["upgrade"],"order":3100,"owners":["ecommerce.progression.managed-support"],"path":"prompts/modular/managed-support.md","sha256":"33abfe9e7514c6826df60572557d54f2e1570477afeae14c64bb3c5f3bad5fb6","until":null},{"from":"## Durable restocks","id":"ecommerce.l3.durable-restocks","modes":["upgrade"],"order":3101,"owners":["ecommerce.l3.deferred-durability-specifications"],"path":"prompts/modular/l3-specifications.md","requiresFeatures":["ecommerce.l3.scheduled-restocks-features"],"sha256":"40c3fac2bde0e10b85416906bcd0080e9748c916820ca44918074f2d342f7deb","until":"## Durable order delivery"},{"from":"## Durable order delivery","id":"ecommerce.l3.durable-order-delivery","modes":["upgrade"],"order":3102,"owners":["ecommerce.l3.deferred-durability-specifications"],"path":"prompts/modular/l3-specifications.md","requiresFeatures":["ecommerce.l3.order-delivery-features"],"sha256":"56a0e9d3113f8c49d563d6a99940e8ee272c32adb841c1dbb5533b17705a1e69","until":"## Durable cart expiration"},{"from":"## Durable cart expiration","id":"ecommerce.l3.durable-cart-expiration","modes":["upgrade"],"order":3103,"owners":["ecommerce.l3.deferred-durability-specifications"],"path":"prompts/modular/l3-specifications.md","requiresFeatures":["ecommerce.l3.cart-expiration-features"],"sha256":"1c81d51182e1a7648dc8e1e34cf1e80aade556a1eaeb63f79ba49b50bf2c2997","until":"## Exactly-once restocks"},{"from":"## Exactly-once restocks","id":"ecommerce.l3.exactly-once-restocks","modes":["upgrade"],"order":3110,"owners":["ecommerce.l3.deferred-integrity-specifications"],"path":"prompts/modular/l3-specifications.md","requiresFeatures":["ecommerce.l3.scheduled-restocks-features"],"sha256":"2fe8adca82a8fd5bb0fa1ba02cbb88e9f4ae3c799c49cf0980451d85603b6515","until":"## Exactly-once delivery"},{"from":"## Exactly-once delivery","id":"ecommerce.l3.exactly-once-delivery","modes":["upgrade"],"order":3111,"owners":["ecommerce.l3.deferred-integrity-specifications"],"path":"prompts/modular/l3-specifications.md","requiresFeatures":["ecommerce.l3.order-delivery-features"],"sha256":"70fa7a5b7e6a074950652a574684c4230545cd3b3b21645e568edf45dea5d44f","until":"## Server-timed restocks"},{"from":"## Server-timed restocks","id":"ecommerce.l3.server-timed-restocks","modes":["upgrade"],"order":3120,"owners":["ecommerce.l3.server-time-specifications"],"path":"prompts/modular/l3-specifications.md","requiresFeatures":["ecommerce.l3.scheduled-restocks-features"],"sha256":"ffb402340b8e0afa1973da971a48ed9534bf615e36c213dc892f7dc7260a9da3","until":"## Server-timed reservations"},{"from":"## Server-timed reservations","id":"ecommerce.l3.server-timed-reservations","modes":["upgrade"],"order":3121,"owners":["ecommerce.l3.server-time-specifications"],"path":"prompts/modular/l3-specifications.md","requiresFeatures":["ecommerce.l3.reservations-features"],"sha256":"108cb53bdda3f4a651347cec50a2236bb5cbbb01b9f92943fd6d287f151789bc","until":"## Deferred-work access"},{"from":"## Deferred-work access","id":"ecommerce.l3.deferred-access","modes":["upgrade"],"order":3130,"owners":["ecommerce.l3.deferred-access-specifications"],"path":"prompts/modular/l3-specifications.md","requiresFeatures":["ecommerce.l3.scheduled-restocks-features"],"sha256":"72874aad78d6da1f467443015f53f82514e45866b09a17c6435b16ec72b4e26f","until":"## Stock conservation"},{"from":"## Stock conservation","id":"ecommerce.l3.stock-conservation","modes":["upgrade"],"order":3140,"owners":["ecommerce.l3.deferred-integrity-specifications"],"path":"prompts/modular/l3-specifications.md","requiresFeatures":["ecommerce.l3.reservations-features"],"sha256":"cf7ef3381b7b3d4beee90d314b4a00d667a89909b67d6fd57f453329a6c48be3","until":null},{"from":null,"id":"ecommerce.progression.promotion-checkout","modes":["upgrade"],"order":3200,"owners":["ecommerce.progression.promotion-checkout"],"path":"prompts/modular/promotion-checkout.md","sha256":"1979ce8991b38fab30c4ea0d0fb7adba51d79bb82981059b0dafded82fed843a","until":null},{"from":null,"id":"ecommerce.progression.stock-alerts","modes":["upgrade"],"order":3300,"owners":["ecommerce.progression.stock-alerts"],"path":"prompts/modular/stock-alerts.md","sha256":"3478629a2831e04baca5eec1d3a2a3695c03f6044c36b43acb7c8ca7e35e9867","until":null},{"from":null,"id":"ecommerce.progression.faceted-search","modes":["upgrade"],"order":4000,"owners":["ecommerce.progression.faceted-search"],"path":"prompts/modular/faceted-search.md","sha256":"5dc13b47abcbc85654c82148f44b854979d868578db50db42e060c773edc2207","until":null},{"from":null,"id":"ecommerce.progression.personalized-recommendations","modes":["upgrade"],"order":4010,"owners":["ecommerce.progression.personalized-recommendations"],"path":"prompts/modular/progression-personalized-recommendations.md","sha256":"6c78b3963318b18da11173f96bed5cb8e5537f49e0008342ff11209fada3e099","until":null},{"from":null,"id":"ecommerce.spec.search-ordering","modes":["fresh","upgrade"],"order":4010,"owners":["ecommerce.spec.search-ordering"],"path":"prompts/modular/search-ordering-specification.md","requiresFeatures":["ecommerce.feature.purchasing","ecommerce.progression.faceted-search"],"sha256":"77d88f2b03c71b6cdc8350020ffd7815cf0bee87e4155c1aa00beb9bb81a83f8","until":null},{"from":null,"id":"ecommerce.l3.order-returns","modes":["upgrade"],"order":4040,"owners":["ecommerce.l3.order-returns-features"],"path":"prompts/modular/order-returns.md","sha256":"7277266f1e8c7d660ee38ba55ac1359200e56c695862c6d7d755d6ec6a6cb808","until":null},{"from":null,"id":"ecommerce.progression.order-support","modes":["upgrade"],"order":4100,"owners":["ecommerce.progression.order-support"],"path":"prompts/modular/order-support.md","sha256":"f515fe9827373e110633245df158ce8f78ca040f6c25a059d3885182515abb9a","until":null},{"from":null,"id":"ecommerce.progression.promotion-reporting","modes":["upgrade"],"order":4200,"owners":["ecommerce.progression.promotion-reporting"],"path":"prompts/modular/promotion-reporting.md","sha256":"3285eb0a50ceeed40b3415bdab8d6f5fc4138e496d2062a08c5ee2fac70157c6","until":null},{"from":null,"id":"ecommerce.progression.delivery-notifications","modes":["upgrade"],"order":5000,"owners":["ecommerce.progression.delivery-notifications"],"path":"prompts/modular/delivery-notifications.md","sha256":"12d6db9061749779dcb3db699a492781b34ae955c4c11cbb3e5dc2c8e0300ef3","until":null},{"from":null,"id":"ecommerce.progression.automatic-reorder","modes":["upgrade"],"order":5010,"owners":["ecommerce.progression.automatic-reorder"],"path":"prompts/modular/progression-automatic-reorder.md","sha256":"64751064e699c709a6550daba6fee8f019f445b817910e1ed0d8831632fa2471","until":null},{"from":null,"id":"ecommerce.progression.cart-recovery","modes":["upgrade"],"order":5020,"owners":["ecommerce.progression.cart-recovery"],"path":"prompts/modular/progression-cart-recovery.md","sha256":"4dc64aaa87d54a05bd7cce31bdc98254e605251d14f1688b859e9aa908da6a8b","until":null},{"from":null,"id":"ecommerce.progression.recommendation-feedback","modes":["upgrade"],"order":5030,"owners":["ecommerce.progression.recommendation-feedback"],"path":"prompts/modular/recommendation-feedback.md","sha256":"072a548ae797773041e86cbc62f39011559ca7ab40441bee6b77ec1854cd7f51","until":null},{"from":null,"id":"ecommerce.feature.store-credit","modes":["upgrade"],"order":5100,"owners":["ecommerce.feature.store-credit"],"path":"prompts/modular/store-credit.md","sha256":"d769da6c0ef4eb2fa6ac241aeddb61e8e2d85a0f1fcfd595fbf2c6660f67cd7b","until":null},{"from":null,"id":"ecommerce.feature.subscriptions","modes":["upgrade"],"order":5100,"owners":["ecommerce.feature.subscriptions"],"path":"prompts/modular/subscriptions.md","sha256":"ca93ab01c0d23c2fb3c035981372dc1254b219f1875b9566c0d01123176cc7c1","until":null},{"from":null,"id":"ecommerce.progression.support-refunds","modes":["upgrade"],"order":5100,"owners":["ecommerce.progression.support-refunds"],"path":"prompts/modular/support-refunds.md","sha256":"79090320de03a74660418da9e9adbf8170f8c574be990faeaf3d7df652221aa6","until":null},{"from":"## automatic-reorder-access","id":"ecommerce.spec.access-control.automatic-reorder-access","modes":["upgrade"],"order":6001,"owners":["ecommerce.spec.access-control"],"path":"prompts/modular/production-specifications.md","requiresFeatures":["ecommerce.progression.automatic-reorder"],"sha256":"f93257ed878a9fc27e9a0b80ceb050ab44e5ced5f6ba3d868939e8dee9ed49b1","until":"## recommendation-profile-isolation"},{"from":"## recommendation-profile-isolation","id":"ecommerce.spec.access-control.recommendation-profile-isolation","modes":["upgrade"],"order":6002,"owners":["ecommerce.spec.access-control"],"path":"prompts/modular/production-specifications.md","requiresFeatures":["ecommerce.progression.personalized-recommendations"],"sha256":"36fe3efec8aa2529e48f5f2ef809256a97957554e2a349e669fddcc3d6942a5a","until":"## staff-activity-privacy"},{"from":"## staff-activity-privacy","id":"ecommerce.spec.access-control.staff-activity-privacy","modes":["upgrade"],"order":6003,"owners":["ecommerce.spec.access-control"],"path":"prompts/modular/production-specifications.md","requiresFeatures":["ecommerce.progression.staff-activity"],"sha256":"3d9a91bd3c10abf3594a2dc690077f5a3b1ed95ddb7257c7c49f8e666448949c","until":"## order-support-ownership"},{"from":"## order-support-ownership","id":"ecommerce.spec.access-control.order-support-ownership","modes":["upgrade"],"order":6004,"owners":["ecommerce.spec.access-control"],"path":"prompts/modular/production-specifications.md","requiresFeatures":["ecommerce.progression.order-support"],"sha256":"5e090901a9bbfe7b0f1869be90a16d8d9df30b735effc5cd55e63784443aad05","until":"## delivery-notification-privacy"},{"from":"## delivery-notification-privacy","id":"ecommerce.spec.access-control.delivery-notification-privacy","modes":["upgrade"],"order":6005,"owners":["ecommerce.spec.access-control"],"path":"prompts/modular/production-specifications.md","requiresFeatures":["ecommerce.feature.purchasing","ecommerce.progression.delivery-notifications","ecommerce.progression.fulfilment-queue"],"sha256":"4fbdbdc513c7cc363198ce55780a421261c057f54ac8a44e3a69908d792d2e22","until":"## support-refund-access"},{"from":"## support-refund-access","id":"ecommerce.spec.access-control.support-refund-access","modes":["upgrade"],"order":6006,"owners":["ecommerce.spec.access-control"],"path":"prompts/modular/production-specifications.md","requiresFeatures":["ecommerce.progression.support-refunds"],"sha256":"a4200b390cf7c85d467425834af2642ceb7a80fa9ee53cccdfaa565d6ff69684","until":"## recommendation-feedback-privacy"},{"from":"## recommendation-feedback-privacy","id":"ecommerce.spec.access-control.recommendation-feedback-privacy","modes":["upgrade"],"order":6007,"owners":["ecommerce.spec.access-control"],"path":"prompts/modular/production-specifications.md","requiresFeatures":["ecommerce.progression.recommendation-feedback"],"sha256":"3df273f53ccd54520a89fedb64952b990ff4f61c36d16a50bd1f28e8523471b2","until":"## recommendation-feedback-restart"},{"from":"## recommendation-feedback-restart","id":"ecommerce.spec.state-durability.recommendation-feedback-restart","modes":["upgrade"],"order":6008,"owners":["ecommerce.spec.state-durability"],"path":"prompts/modular/production-specifications.md","requiresFeatures":["ecommerce.progression.recommendation-feedback"],"sha256":"5531638e5123f8c7c76c6f095ba3dadb52128482acc6d325de997ec280656d7c","until":"## automatic-reorder-deduplication"},{"from":"## automatic-reorder-deduplication","id":"ecommerce.spec.transactional-integrity.automatic-reorder-deduplication","modes":["upgrade"],"order":6009,"owners":["ecommerce.spec.transactional-integrity"],"path":"prompts/modular/production-specifications.md","requiresFeatures":["ecommerce.feature.purchasing","ecommerce.progression.automatic-reorder"],"sha256":"de82b9029ce5ae8c90dc1ea20a024da19d8ea55eac6ab36f6fa1d84b8b241b01","until":"## payment-deduplication"},{"from":"## payment-deduplication","id":"ecommerce.spec.transactional-integrity.payment-deduplication","modes":["upgrade"],"order":6010,"owners":["ecommerce.spec.transactional-integrity"],"path":"prompts/modular/production-specifications.md","requiresFeatures":["ecommerce.progression.payment-records"],"sha256":"f33fb61f31726bbe7e8b617ae12d970a8d876d98d30d49191dd0043a58557760","until":"## support-refund-accounting"},{"from":"## support-refund-accounting","id":"ecommerce.spec.transactional-integrity.support-refund-accounting","modes":["upgrade"],"order":6011,"owners":["ecommerce.spec.transactional-integrity"],"path":"prompts/modular/production-specifications.md","requiresFeatures":["ecommerce.progression.support-refunds"],"sha256":"bd44a5a8c9211493896869df9b086177b022d9840f9a362d0c609e3c6bff6877","until":null},{"from":null,"id":"ecommerce.feature.split-tender-refunds","modes":["upgrade"],"order":6100,"owners":["ecommerce.feature.split-tender-refunds"],"path":"prompts/modular/split-tender-refunds.md","sha256":"c21e00af3623136de4ae45f089b45b457a34563eb37a756d5b8b3563d1f19734","until":null},{"from":"## Product bundles","id":"ecommerce.spec.bundle-integrity.product-bundles","modes":["fresh","upgrade"],"order":6500,"owners":["ecommerce.spec.bundle-integrity"],"path":"prompts/modular/later-specifications.md","requiresFeatures":["ecommerce.feature.product-bundles"],"sha256":"7eb9ee1c794134867f6b27ad3b773bbd99d4c860774618d1286d39b4347470fb","until":"## Bundle checkout"},{"from":"## Bundle checkout","id":"ecommerce.spec.bundle-integrity.bundle-checkout","modes":["fresh","upgrade"],"order":6501,"owners":["ecommerce.spec.bundle-integrity"],"path":"prompts/modular/later-specifications.md","requiresFeatures":["ecommerce.feature.bundle-checkout"],"sha256":"630eead6de0dc2d9672e83e64beb8cb5036eccd9ba4aaf7c9284d91c0e42144b","until":"## Bundle returns"},{"from":"## Bundle returns","id":"ecommerce.spec.bundle-integrity.bundle-returns","modes":["fresh","upgrade"],"order":6502,"owners":["ecommerce.spec.bundle-integrity"],"path":"prompts/modular/later-specifications.md","requiresFeatures":["ecommerce.feature.bundle-returns"],"sha256":"7a2264753c8088c30ecc87cb1f98940198fde663b5a4a1bb8de83c410e01e5b2","until":"## Store credit"},{"from":"## Store credit","id":"ecommerce.spec.store-credit.store-credit","modes":["fresh","upgrade"],"order":6503,"owners":["ecommerce.spec.store-credit"],"path":"prompts/modular/later-specifications.md","requiresFeatures":["ecommerce.feature.store-credit"],"sha256":"ee64f04e0f30fc269021083c4b02c26f9fc87321d41d7a7262e68bf6926b7c83","until":"## Split-tender refunds"},{"from":"## Split-tender refunds","id":"ecommerce.spec.split-tender-refunds.split-tender-refunds","modes":["fresh","upgrade"],"order":6504,"owners":["ecommerce.spec.split-tender-refunds"],"path":"prompts/modular/later-specifications.md","requiresFeatures":["ecommerce.feature.split-tender-refunds"],"sha256":"860929486a2d9e283be8486c85b1ee2086936b22de28db17febf5a1e65bc10ff","until":"## Scheduled purchases"},{"from":"## Scheduled purchases","id":"ecommerce.spec.subscriptions.subscriptions","modes":["fresh","upgrade"],"order":6505,"owners":["ecommerce.spec.subscriptions"],"path":"prompts/modular/later-specifications.md","requiresFeatures":["ecommerce.feature.subscriptions"],"sha256":"69f32aaf688858b89cb8fc56352b1674e13fd18b7b9454da3ba9a025e24c90ab","until":null},{"from":null,"id":"ecommerce.feature.product-bundles","modes":["upgrade"],"order":8004,"owners":["ecommerce.feature.product-bundles"],"path":"prompts/modular/product-bundles.md","sha256":"a0805178ebbb20ea290994de65b4ded503c37798af59905d47c1cb2fd4e2c467","until":null},{"from":null,"id":"ecommerce.feature.bundle-checkout","modes":["upgrade"],"order":8005,"owners":["ecommerce.feature.bundle-checkout"],"path":"prompts/modular/bundle-checkout.md","sha256":"d3f21ac08991619b5c9aa6ac99a7554340bae991d5b31a25cdb048cdb314936e","until":null},{"from":null,"id":"ecommerce.feature.bundle-returns","modes":["upgrade"],"order":8006,"owners":["ecommerce.feature.bundle-returns"],"path":"prompts/modular/bundle-returns.md","sha256":"34b3bee882e6a1f6a1527e67d12f8cbdcfd74d026108f9805159123c41015bf2","until":null}]},"title":"Ecommerce progression catalog","track":"ecommerce"},"meaning":{"checks":[{"category":"feature","checkGroupId":"accounts","criterionId":"1a","description":"a visitor can create an account and is signed in as it","featureId":1,"featureName":"Accounts","note":null,"packId":"ecommerce.feature.accounts","points":1,"provenBy":null,"role":"feature","semantics":[{"do":"signUp","name":"ann"},{"contains":"ann","do":"expect"}],"source":"scenarios/01-account-create.json","stableKey":"ecommerce.feature.accounts.accounts.1a","statedBy":"a visitor can create an account with a username and password","withheld":null},{"category":"production","checkGroupId":"accounts","criterionId":"1b","description":"a taken username is refused and does not sign the visitor in as the existing account","featureId":1,"featureName":"Accounts","note":null,"packId":"ecommerce.feature.accounts","points":1,"provenBy":null,"role":"feature","semantics":[{"do":"signUp","expectFailure":true,"name":"ann","password":"different-pw"},{"do":"expect"},{"absent":true,"do":"expect"}],"source":"scenarios/01-account-duplicate.json","stableKey":"ecommerce.feature.accounts.accounts.1b","statedBy":"signing up with a taken username fails with a visible error and must never sign the visitor in as the existing account","withheld":null},{"category":"production","checkGroupId":"accounts","criterionId":"1c","description":"a wrong password is refused","featureId":1,"featureName":"Accounts","note":null,"packId":"ecommerce.feature.accounts","points":1,"provenBy":null,"role":"feature","semantics":[{"do":"signIn","expectFailure":true,"name":"ann","password":"wrong-pw"},{"do":"expect"},{"absent":true,"do":"expect"}],"source":"scenarios/01-account-password.json","stableKey":"ecommerce.feature.accounts.accounts.1c","statedBy":"signing in with a wrong password fails with a visible error","withheld":null},{"category":"production","checkGroupId":"session-reload","criterionId":"1e","description":"the session survives a reload","featureId":1,"featureName":"Accounts","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.state-durability","points":1,"provenBy":null,"requiresFeatures":["ecommerce.feature.accounts"],"role":"guarantee","semantics":[{"do":"reload"},{"contains":"ann","do":"expect"}],"source":"scenarios/01-account-reload.json","stableKey":"ecommerce.spec.state-durability.session-reload.1e","statedBy":"a signed-in session persists across a page reload","withheld":null},{"category":"feature","checkGroupId":"accounts","criterionId":"1d","description":"signing out and back in returns the same account","featureId":1,"featureName":"Accounts","note":null,"packId":"ecommerce.feature.accounts","points":1,"provenBy":null,"role":"feature","semantics":[{"do":"click","unlessVisible":"signout"},{"do":"click"},{"do":"waitUntilAbsent"},{"do":"signIn","name":"ann"},{"contains":"ann","do":"expect"}],"source":"scenarios/01-account-signout.json","stableKey":"ecommerce.feature.accounts.accounts.1d","statedBy":"a signed-in user can sign out, returning to the signed-out state","withheld":null},{"category":"feature","checkGroupId":"admin-write","criterionId":"103a","description":"an administrator can restock a warehouse","featureId":103,"featureName":"Only an administrator can restock","note":null,"packId":"ecommerce.feature.warehouse-admin","points":1,"provenBy":null,"role":"feature","semantics":[{"as":"purifier-before-control","do":"recordNumber"},{"action":"restock","do":"callAction","input":{"attribute":"data-restock-input","contains":"Air Purifier","testid":"admin-location-row"},"namedAction":{"args":[0,0,1],"id":"restock","params":[{"in":"body","name":"itemId","wireType":"u64"},{"in":"body","name":"warehouseId","wireType":"u64"},{"in":"body","name":"quantity"}],"path":"/api/admin/restock","reducer":"admin_restock"}},{"do":"expectActionOutcome","outcome":"accepted"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"do":"expectNumber","plus":1,"relativeTo":"purifier-before-control"}],"source":"scenarios/01-admin-write-staff.json","stableKey":"ecommerce.feature.warehouse-admin.admin-write.103a","statedBy":"An administrator can add units to a selected item and warehouse.","withheld":null},{"category":"production","checkGroupId":"warehouse-write-boundary","criterionId":"103b","description":"the server refuses a warehouse write from staff","featureId":103,"featureName":"Only an administrator can restock","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"provenBy":null,"requiresFeatures":["ecommerce.feature.warehouse-admin"],"role":"guarantee","semantics":[{"action":"restock","do":"callAction","input":{"attribute":"data-restock-input","contains":"Air Purifier","testid":"admin-location-row"},"namedAction":{"args":[0,0,1],"id":"restock","params":[{"in":"body","name":"itemId","wireType":"u64"},{"in":"body","name":"warehouseId","wireType":"u64"},{"in":"body","name":"quantity"}],"path":"/api/admin/restock","reducer":"admin_restock"}},{"do":"expectActionOutcome","outcome":"accepted"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"as":"purifier-before-refusal","do":"recordNumber"},{"action":"restock","do":"callAction","from":"admin","input":{"attribute":"data-restock-input","contains":"Air Purifier","testid":"admin-location-row"},"namedAction":{"args":[0,0,1],"id":"restock","params":[{"in":"body","name":"itemId","wireType":"u64"},{"in":"body","name":"warehouseId","wireType":"u64"},{"in":"body","name":"quantity"}],"path":"/api/admin/restock","reducer":"admin_restock"}},{"do":"expectActionOutcome","outcome":"refused","routeProvenBy":"admin"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"do":"expectNumber","plus":0,"relativeTo":"purifier-before-refusal"}],"source":"scenarios/01-admin-write-staff.json","stableKey":"ecommerce.spec.access-control.warehouse-write-boundary.103b","statedBy":"Only administrators can change warehouse stock.","withheld":null},{"category":"production","checkGroupId":"purchase-stock","criterionId":"3b","description":"buying reduces the stock every other client sees, without a reload","featureId":3,"featureName":"Buying","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.live-state","points":2,"provenBy":null,"requiresFeatures":["ecommerce.feature.catalog-items","ecommerce.feature.purchasing"],"role":"guarantee","semantics":[{"do":"expectNumber","equals":100},{"do":"click"},{"do":"expectNumber","equals":99},{"do":"expectNumber","equals":99}],"source":"scenarios/01-buying.json","stableKey":"ecommerce.spec.live-state.purchase-stock.3b","statedBy":"buying an item reduces its stock by one for everyone","withheld":null},{"category":"production","checkGroupId":"cart-boundary","criterionId":"109a","description":"the same cart action run by another customer changes only that customer's cart","featureId":109,"featureName":"A cart is nobody else's business","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"provenBy":null,"requiresFeatures":["ecommerce.feature.cart"],"role":"guarantee","semantics":[{"action":"cart-add","do":"callAction","input":{"attribute":"data-buy-input","contains":"Coffee Grinder","testid":"item-card"},"namedAction":{"args":[0],"id":"cart-add","params":[{"in":"body","name":"itemId","wireType":"u64"}],"path":"/api/cart","reducer":"add_to_cart"}},{"do":"expectActionOutcome","outcome":"accepted"},{"do":"reload"},{"do":"ensureSignedIn","name":"vic"},{"do":"click","ifAvailable":true},{"do":"click","ifAvailable":true},{"do":"click","unlessVisible":"cart-total"},{"do":"reload"},{"do":"ensureSignedIn","name":"wes"},{"do":"click","ifAvailable":true},{"do":"click","ifAvailable":true},{"contains":"Coffee Grinder","count":1,"do":"expect"},{"do":"expectNumber","equals":1},{"do":"click","unlessVisible":"cart-total"},{"contains":"Coffee Grinder","count":1,"do":"expect"},{"do":"expectNumber","equals":1}],"source":"scenarios/01-cart-boundary.json","stableKey":"ecommerce.spec.access-control.cart-boundary.109a","statedBy":"one customer cannot read or change another customer's cart","withheld":null},{"category":"production","checkGroupId":"cart-boundary","criterionId":"109b","description":"a negative quantity is refused and leaves the cart unchanged","featureId":109,"featureName":"A cart is nobody else's business","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":1,"provenBy":null,"requiresFeatures":["ecommerce.feature.cart"],"role":"guarantee","semantics":[{"as":"cart-total-before-invalid","do":"recordNumber"},{"as":"cart-quantity-before-invalid","do":"recordNumber"},{"action":"cart-set-quantity","do":"callAction","input":{"attribute":"data-cart-input","contains":"Coffee Grinder","testid":"cart-item"},"namedAction":{"args":[0,-3],"id":"cart-set-quantity","method":"PATCH","params":[{"in":"path","name":"itemId","placeholder":":itemId","wireType":"u64"},{"in":"body","name":"quantity"}],"path":"/api/cart/:itemId","reducer":"update_cart_quantity"}},{"do":"expectActionOutcome","outcome":"validation-refused"},{"do":"reload"},{"do":"ensureSignedIn","name":"vic"},{"do":"click","ifAvailable":true},{"do":"click","ifAvailable":true},{"do":"click","unlessVisible":"cart-total"},{"do":"expectNumber","plus":0,"relativeTo":"cart-total-before-invalid"},{"do":"expectNumber","plus":0,"relativeTo":"cart-quantity-before-invalid"}],"source":"scenarios/01-cart-boundary.json","stableKey":"ecommerce.spec.access-control.cart-boundary.109b","statedBy":"a request carrying a negative quantity is refused and changes nothing","withheld":null},{"category":"production","checkGroupId":"cart-reload","criterionId":"4b","description":"the cart survives a reload","featureId":4,"featureName":"Cart belongs to the account","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.state-durability","points":1,"provenBy":null,"requiresFeatures":["ecommerce.feature.cart"],"role":"guarantee","semantics":[{"do":"click"},{"do":"click","unlessVisible":"cart-total"},{"contains":"Laptop Stand","do":"expect"},{"do":"reload"},{"do":"ensureSignedIn","name":"omar"},{"do":"click","unlessVisible":"cart-total"},{"contains":"Laptop Stand","do":"expect"}],"source":"scenarios/01-cart.json","stableKey":"ecommerce.spec.state-durability.cart-reload.4b","statedBy":"the cart survives a reload","withheld":null},{"category":"production","checkGroupId":"shared-cart","criterionId":"4c","description":"the same account signed in elsewhere sees one cart, live","featureId":4,"featureName":"Cart belongs to the account","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.live-state","points":2,"provenBy":null,"requiresFeatures":["ecommerce.feature.cart"],"role":"guarantee","semantics":[{"do":"signIn","name":"pia"},{"do":"click","unlessVisible":"cart-total"},{"do":"click"},{"contains":"Induction Cooktop","do":"expect"}],"source":"scenarios/01-cart.json","stableKey":"ecommerce.spec.live-state.shared-cart.4c","statedBy":"the same account signed in twice sees one cart, and a change made in one place appears in the other without a reload","withheld":null},{"category":"feature","checkGroupId":"catalog-ranking","criterionId":"2b","description":"the storefront shows the exact alphabetical top ten before any purchase","featureId":2,"featureName":"Public catalog ranking","note":null,"packId":"ecommerce.feature.catalog-discovery","points":1,"provenBy":null,"role":"feature","semantics":[{"do":"expectSequence","equals":["Air Purifier","Bluetooth Speaker","Coffee Grinder","Desk Lamp","Espresso Machine","Gaming Mouse","Headphones","Induction Cooktop","Keyboard","Laptop Stand"]}],"source":"scenarios/01-catalog-ranking.json","stableKey":"ecommerce.feature.catalog.catalog-ranking.2b","statedBy":"Show the ten most-purchased items and break ties by item name","withheld":null},{"category":"feature","checkGroupId":"catalog-search","criterionId":"2d","description":"case-insensitive partial search finds an item outside the storefront top ten","featureId":2,"featureName":"Public catalog search","note":null,"packId":"ecommerce.feature.catalog-discovery","points":1,"provenBy":null,"role":"feature","semantics":[{"do":"fill","enter":true,"text":"mirrorLESS"},{"contains":"Mirrorless Camera","do":"expect"}],"source":"scenarios/01-catalog-search.json","stableKey":"ecommerce.feature.catalog.catalog-search.2d","statedBy":"Search matches any part of an item name without regard to case across the full catalog","withheld":null},{"category":"feature","checkGroupId":"catalog-values","criterionId":"2a","description":"a signed-out visitor sees the seeded item name, price, and total stock","featureId":2,"featureName":"Public catalog values","note":null,"packId":"ecommerce.feature.catalog-items","points":1,"provenBy":null,"role":"feature","semantics":[{"contains":"Air Purifier","do":"expect"},{"do":"expectNumber","equals":189},{"do":"expectNumber","equals":100}],"source":"scenarios/01-catalog-values.json","stableKey":"ecommerce.feature.catalog.catalog-values.2a","statedBy":"Each item shows its name, price, and total stock","withheld":null},{"category":"production","checkGroupId":"ranking","criterionId":"2c","description":"a purchase moves the bought item to the front of the ranking, live","featureId":2,"featureName":"Storefront is public and live","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.live-state","points":1,"provenBy":null,"requiresFeatures":["ecommerce.feature.catalog-items","ecommerce.feature.purchasing"],"role":"guarantee","semantics":[{"do":"click"},{"do":"expectSequence","equals":["Coffee Grinder","Air Purifier","Bluetooth Speaker","Desk Lamp","Espresso Machine","Gaming Mouse","Headphones","Induction Cooktop","Keyboard","Laptop Stand"]},{"do":"expectAgreement","numeric":true}],"source":"scenarios/01-core.json","stableKey":"ecommerce.spec.live-state.ranking.2c","statedBy":"a purchase immediately changes the ranking for every open client","withheld":null},{"category":"production","checkGroupId":"duplicate-checkout","criterionId":"203a","description":"the same item added from two tabs at once becomes one line of two","featureId":203,"featureName":"One cart, two tabs, one checkout","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.concurrency-safety","points":1,"provenBy":null,"requiresFeatures":["ecommerce.feature.checkout"],"role":"guarantee","semantics":[{"contains":"Gaming Mouse","count":1,"do":"expect"},{"do":"expectNumber","equals":2}],"source":"scenarios/01-duplicate-checkout.json","stableKey":"ecommerce.spec.concurrency-safety.duplicate-checkout.203a","statedBy":"raises its quantity rather than adding a second line","withheld":null},{"category":"production","checkGroupId":"duplicate-checkout","criterionId":"203b","description":"checking the same cart out twice at once produces one order","featureId":203,"featureName":"One cart, two tabs, one checkout","note":"callConcurrently resolves the track's named checkout action through the selected backend adapter and issues it at the same time with tab1 and tab2's own session credentials. The filler prepares the shared Keyboard cart. Native order evidence requires one complete order for that account, the booked price and quantity, a cleared cart, and unchanged prior orders. Checkout can precede warehouse administration, so this check reads no warehouse data and retains its visible stock reduction assertion. The second call may succeed idempotently or deliberately refuse; server errors and no progress fail.","observations":["requested","unmentioned"],"packId":"ecommerce.spec.concurrency-safety","points":1,"provenBy":"The L1 2.3 candidate set binds an exact 203b defect on every reference stack: MongoDB bypasses the atomic cart claim-and-clear, while PostgreSQL and SpacetimeDB leave checked-out cart lines behind. These defects let both named checkout calls reuse the same cart, which the call-outcome and final order assertions are designed to catch. Exact Docker mutation qualification remains the promotion gate.","requiresFeatures":["ecommerce.feature.checkout"],"role":"guarantee","semantics":[{"do":"click"},{"do":"wait"},{"as":"keyboard-before-checkout","do":"recordNumber"},{"account":"{user:twin}","as":"checkout-before","do":"dbRecordCheckout","item":"Keyboard","storage":{"cart":true,"kind":"order-data","warehouses":false}},{"do":"click"},{"do":"wait"},{"account":"{user:twin}","as":"checkout-prepared","do":"dbRecordCheckout","item":"Keyboard","storage":{"cart":true,"kind":"order-data","warehouses":false}},{"action":"checkout","do":"callConcurrently"},{"do":"expectCallOutcomes"},{"before":"checkout-before","do":"dbExpectCheckout","prepared":"checkout-prepared","quantity":1},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"contains":"Keyboard","count":1,"do":"expect"},{"do":"reload"},{"do":"ensureSignedIn","name":"twin"},{"do":"click","ifAvailable":true},{"do":"click","ifAvailable":true},{"do":"expectNumber","plus":-1,"relativeTo":"keyboard-before-checkout"}],"source":"scenarios/01-duplicate-checkout.json","stableKey":"ecommerce.spec.concurrency-safety.duplicate-checkout.203b","statedBy":"checking out twice must not produce two orders","withheld":"The named checkout action has an HTTP route for MongoDB and PostgreSQL and a reducer mapping for SpacetimeDB. The stack adapter issues the corresponding credentialed request for each actor, giving all three stacks the same one-cart, two-call expectation."},{"category":"production","checkGroupId":"external-stock","criterionId":"901a","description":"a direct database write sets Desk Lamp's East stock to 5, and the already-open storefront updates from 100 to 50 without a reload or page action","featureId":901,"featureName":"An open storefront follows a direct database write","note":"This proposed score remains draft until the focused pristine and mutation controls are qualified.","observations":["requested","unmentioned"],"packId":"ecommerce.spec.external-data-sync","points":1,"provenBy":null,"requiresFeatures":["ecommerce.feature.warehouse-admin"],"role":"guarantee","semantics":[{"do":"dbSetStock","item":"Desk Lamp","quantity":5,"warehouse":"East"},{"do":"expectNumber","equals":50}],"source":"scenarios/01-external-live-sync.json","stableKey":"ecommerce.spec.external-data-sync.external-stock.901a","statedBy":"The storefront reflects current database values after changes made outside the application server.","withheld":null},{"category":"production","checkGroupId":"external-stock","criterionId":"901d","description":"while the storefront is offline, a direct database write sets Desk Lamp's East stock to 7; after reconnecting, the same page catches up from 100 to the authoritative total of 52","featureId":901,"featureName":"A reconnecting storefront catches up to an external write","note":"This proposed score remains draft until the focused pristine and mutation controls are qualified.","observations":["requested","unmentioned"],"packId":"ecommerce.spec.external-data-sync","points":1,"provenBy":null,"requiresFeatures":["ecommerce.feature.warehouse-admin"],"role":"guarantee","semantics":[{"do":"setOffline","offline":true},{"do":"dbSetStock","item":"Desk Lamp","quantity":7,"warehouse":"East"},{"do":"setOffline","offline":false},{"do":"expectNumber","equals":52}],"source":"scenarios/01-external-reconnect-sync.json","stableKey":"ecommerce.spec.external-data-sync.external-stock.901d","statedBy":"The storefront reflects current database values after changes made outside the application server.","withheld":null},{"checkGroupId":"external-stock","criterionId":"901b","description":"after a direct database write sets Desk Lamp's East stock to 5, a reload reads the persisted total of 50","featureId":901,"featureName":"A direct database write survives reload","note":"Supporting evidence for 901a rather than a second score. It rules out a page-only patch but has no distinct calibrated failure mode.","observations":["requested","unmentioned"],"packId":"ecommerce.spec.external-data-sync","points":0,"provenBy":null,"requiresFeatures":["ecommerce.feature.warehouse-admin"],"role":"guarantee","semantics":[{"do":"dbSetStock","item":"Desk Lamp","quantity":5,"warehouse":"East"},{"do":"reload"},{"do":"expectNumber","equals":50}],"source":"scenarios/01-external-reload-sync.json","stableKey":"ecommerce.spec.external-data-sync.external-stock.901b","statedBy":"The storefront reflects current database values after changes made outside the application server.","withheld":null},{"category":"production","checkGroupId":"external-stock","criterionId":"901c","description":"a stock correction lands while the app server is stopped, and the already-open storefront shows the authoritative total of 65 after the server returns without a reload","featureId":901,"featureName":"An open storefront catches up after its server restarts","note":"Preserves the previously promoted score while removing its dependency on 901a changing East stock first.","observations":["requested","unmentioned"],"packId":"ecommerce.spec.external-data-sync","points":1,"provenBy":null,"requiresFeatures":["ecommerce.feature.warehouse-admin"],"role":"guarantee","semantics":[{"do":"stopAppServer"},{"do":"dbSetStock","item":"Desk Lamp","quantity":10,"warehouse":"West"},{"do":"startAppServer"},{"do":"expectNumber","equals":65}],"source":"scenarios/01-external-server-restart-sync.json","stableKey":"ecommerce.spec.external-data-sync.external-stock.901c","statedBy":"a restart must end up showing the current numbers once the server is back","withheld":null},{"category":"production","checkGroupId":"last-unit","criterionId":"201a","description":"after six customers try to buy the last three units, each warehouse stores zero stock and all observed clients show zero stock","featureId":201,"featureName":"The last unit is sold once","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.concurrency-safety","points":1,"provenBy":"Prior qualification covers the client observations only. The added stored-stock observations need matching three-stack reference and defect-control evidence before promotion.","requiresFeatures":["ecommerce.feature.catalog-items","ecommerce.feature.purchasing","ecommerce.feature.warehouse-admin"],"role":"guarantee","semantics":[{"do":"dbExpectStock","equals":0,"item":"Air Purifier","warehouse":"East"},{"do":"dbExpectStock","equals":0,"item":"Air Purifier","warehouse":"West"},{"do":"expectNumber","equals":0},{"do":"expectAgreement","numeric":true}],"source":"scenarios/01-last-unit.json","stableKey":"ecommerce.spec.concurrency-safety.last-unit.201a","statedBy":"stock may never go negative, and two customers must never both get the last unit","withheld":null},{"category":"production","checkGroupId":"last-unit","criterionId":"201c","description":"revenue increases by exactly three sales, not six","featureId":201,"featureName":"The last unit is sold once","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.concurrency-safety","points":1,"provenBy":null,"requiresFeatures":["ecommerce.feature.catalog-items","ecommerce.feature.purchasing","ecommerce.feature.warehouse-admin"],"role":"guarantee","semantics":[{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","ifAvailable":true},{"do":"click","unlessVisible":"admin-revenue"},{"do":"expectNumber","plus":567,"relativeTo":"revenue-before-last-unit"}],"source":"scenarios/01-last-unit.json","stableKey":"ecommerce.spec.concurrency-safety.last-unit.201c","statedBy":"stock must never leave a warehouse without a corresponding order","withheld":null},{"category":"production","checkGroupId":"last-unit","criterionId":"201b","description":"the last three units create complete orders for the successful buyers, and all four affordable purchases succeed when stock is sufficient","featureId":201,"featureName":"The last unit is sold once","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.concurrency-safety","points":1,"provenBy":"Draft: native order reconciliation and the sufficient-stock progress case require matching reference and defect controls. This criterion runs after the revenue assertion so its extra purchases cannot alter that assertion's baseline.","requiresFeatures":["ecommerce.feature.catalog-items","ecommerce.feature.purchasing","ecommerce.feature.warehouse-admin"],"role":"guarantee","semantics":[{"before":{"a":"buy-a","b":"buy-b","c":"buy-c","d":"buy-d","e":"buy-e","f":"buy-f"},"do":"dbExpectPurchases","purchases":3},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"contains":"Air Purifier","do":"expectActorsWith","equals":3,"maxEach":1},{"do":"dbSetStock","item":"Air Purifier","quantity":2,"warehouse":"East"},{"do":"dbSetStock","item":"Air Purifier","quantity":2,"warehouse":"West"},{"do":"reload"},{"do":"ensureSignedIn","name":"c1"},{"do":"click","ifAvailable":true},{"account":"{user:c1}","as":"ample-a","do":"dbRecordCheckout","item":"Air Purifier","storage":{"cart":false,"kind":"order-data","warehouses":true}},{"account":"{user:c2}","as":"ample-b","do":"dbRecordCheckout","item":"Air Purifier","storage":{"cart":false,"kind":"order-data","warehouses":true}},{"action":"buy","do":"callConcurrently","from":"a","input":{"attribute":"data-buy-input","contains":"Air Purifier","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"},"requests":4},{"do":"expectCallOutcomes"},{"before":{"a":"ample-a","b":"ample-b"},"do":"dbExpectPurchases","purchases":4}],"source":"scenarios/01-last-unit.json","stableKey":"ecommerce.spec.concurrency-safety.last-unit.201b","statedBy":"two customers must never both get the last unit","withheld":null},{"category":"production","checkGroupId":"order-ownership","criterionId":"106a","description":"a working order history contains the customer's own order and not another customer's order","featureId":106,"featureName":"One customer's orders are not another's","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":1,"provenBy":null,"requiresFeatures":["ecommerce.feature.purchasing"],"role":"guarantee","semantics":[{"do":"click"},{"do":"click"},{"do":"wait"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"contains":"Desk Lamp","count":1,"do":"expect"},{"absent":true,"contains":"Coffee Grinder","do":"expect"}],"source":"scenarios/01-order-ownership.json","stableKey":"ecommerce.spec.access-control.order-ownership.106a","statedBy":"a customer sees only their own orders","withheld":null},{"category":"production","checkGroupId":"purchase-attribution","criterionId":"102a","description":"a direct purchase is attributed to the authenticated caller, not another account","featureId":102,"featureName":"Purchases are attributed to whoever made them","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"provenBy":null,"requiresFeatures":["ecommerce.feature.purchasing"],"role":"guarantee","semantics":[{"action":"buy","do":"callAction","input":{"attribute":"data-buy-input","contains":"Desk Lamp","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"}},{"do":"expectActionOutcome","outcome":"accepted"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"contains":"Coffee Grinder","count":1,"do":"expect"},{"absent":true,"contains":"Desk Lamp","do":"expect"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"contains":"Desk Lamp","count":1,"do":"expect"}],"source":"scenarios/01-purchase-attribution.json","stableKey":"ecommerce.spec.access-control.purchase-attribution.102a","statedBy":"the authenticated caller, not a client-supplied identity, owns the order","withheld":null},{"category":"production","checkGroupId":"purchase-session","criterionId":"101a","description":"a valid direct purchase works for the buyer but is refused without a session","featureId":101,"featureName":"Purchase requires an account","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"provenBy":null,"requiresFeatures":["ecommerce.feature.purchasing"],"role":"guarantee","semantics":[{"action":"buy","authentication":"none","do":"callAction","from":"buyer","input":{"attribute":"data-buy-input","contains":"Bluetooth Speaker","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"}},{"do":"expectActionOutcome","outcome":"refused","routeProvenBy":"buyer"},{"do":"dbExpectStock","item":"Bluetooth Speaker","plus":-1,"relativeTo":"speaker-before-control"}],"source":"scenarios/01-purchase-session.json","stableKey":"ecommerce.spec.access-control.purchase-session.101a","statedBy":"the server refuses a purchase without an authenticated customer","withheld":null},{"category":"feature","checkGroupId":"restock-race","criterionId":"202-control","description":"an uncontended restock of five is stored by the server and shows on the storefront","featureId":202,"featureName":"A restock during a rush is not lost","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.concurrency-safety","points":0,"provenBy":null,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.warehouse-admin"],"role":"guarantee","semantics":[{"do":"dbExpectStock","item":"Bluetooth Speaker","plus":5,"relativeTo":"stored-before-control"},{"do":"expectNumber","plus":5,"relativeTo":"storefront-before"}],"source":"scenarios/01-restock-race.json","stableKey":"ecommerce.spec.concurrency-safety.restock-race.202-control","statedBy":null,"withheld":"The ordinary restock is a setup prerequisite retained when only the race is selected. This zero-point control verifies that setup; it does not add product credit."},{"category":"production","checkGroupId":"restock-race","criterionId":"202a","description":"restocking during purchases preserves stock, complete buyer orders and their warehouse allocations","featureId":202,"featureName":"A restock during a rush is not lost","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.concurrency-safety","points":1,"provenBy":null,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.warehouse-admin"],"role":"guarantee","semantics":[{"as":"stored-before-rush","do":"dbRecordStock","item":"Bluetooth Speaker"},{"do":"fill","text":"5"},{"as":"rush-before","do":"recordNumber"},{"branches":[[{"do":"clickConcurrently"}],[{"do":"click"}]],"do":"race"},{"do":"dbExpectStock","item":"Bluetooth Speaker","plus":2,"relativeTo":"stored-before-rush"},{"atLeast":0,"do":"dbExpectStock","item":"Bluetooth Speaker","warehouse":"East"},{"atLeast":0,"do":"dbExpectStock","item":"Bluetooth Speaker","warehouse":"West"},{"do":"reload"},{"do":"click"},{"do":"expectNumber","plus":2,"relativeTo":"rush-before"},{"do":"ensureSignedIn","name":"r1"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"contains":"Bluetooth Speaker","count":2,"do":"expect"},{"do":"reload"},{"do":"ensureSignedIn","name":"r2"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"contains":"Bluetooth Speaker","count":1,"do":"expect"},{"do":"reload"},{"do":"ensureSignedIn","name":"r3"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"contains":"Bluetooth Speaker","count":1,"do":"expect"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","ifAvailable":true},{"do":"expectNumber","plus":2,"relativeTo":"stored-before-rush"},{"do":"reload"},{"do":"click"},{"do":"expectNumber","plus":2,"relativeTo":"stored-before-rush"},{"do":"ensureSignedIn","name":"r1"},{"account":"{user:r1}","as":"mixed-a","do":"dbRecordCheckout","item":"Bluetooth Speaker","storage":{"cart":false,"kind":"order-data","warehouses":true}},{"account":"{user:r2}","as":"mixed-b","do":"dbRecordCheckout","item":"Bluetooth Speaker","storage":{"cart":false,"kind":"order-data","warehouses":true}},{"account":"{user:r3}","as":"mixed-c","do":"dbRecordCheckout","item":"Bluetooth Speaker","storage":{"cart":false,"kind":"order-data","warehouses":true}},{"action":"buy","alongside":[{"action":"restock","actors":["admin"],"input":{"attribute":"data-restock-input","contains":"Bluetooth Speaker","testid":"admin-location-row"},"namedAction":{"args":[0,0,1],"id":"restock","params":[{"in":"body","name":"itemId","wireType":"u64"},{"in":"body","name":"warehouseId","wireType":"u64"},{"in":"body","name":"quantity"}],"path":"/api/admin/restock","reducer":"admin_restock"},"requests":1}],"do":"callConcurrently","from":"a","input":{"attribute":"data-buy-input","contains":"Bluetooth Speaker","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"},"requests":3},{"accepted":4,"do":"expectCallOutcomes"},{"before":{"a":"mixed-a","b":"mixed-b","c":"mixed-c"},"do":"dbExpectPurchases","purchases":3}],"source":"scenarios/01-restock-race.json","stableKey":"ecommerce.spec.concurrency-safety.restock-race.202a","statedBy":"a restock in one warehouse raises the storefront number live","withheld":null},{"category":"production","checkGroupId":"review-eligibility","criterionId":"108a","description":"someone who never bought the item cannot review it","featureId":108,"featureName":"A review is a claim about a purchase","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"provenBy":null,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.reviews"],"role":"guarantee","semantics":[{"action":"buy","do":"callAction","input":{"attribute":"data-buy-input","contains":"Air Purifier","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"}},{"do":"expectActionOutcome","outcome":"accepted"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"contains":"Air Purifier","do":"expect"},{"do":"click","ifAvailable":true},{"do":"click","ifAvailable":true},{"action":"submitReview","do":"callAction","from":"owner","input":{"attribute":"data-buy-input","contains":"Air Purifier","testid":"item-card"},"namedAction":{"args":[0,4,"eligible review control"],"id":"submitReview","method":"POST","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"},{"in":"body","name":"rating"},{"in":"body","name":"comment"}],"path":"/api/items/:id/reviews","reducer":"submit_review"}},{"do":"expectActionOutcome","outcome":"accepted"},{"do":"openItem","item":"Air Purifier"},{"contains":"eligible review control","do":"expect"},{"action":"submitReview","do":"callAction","from":"owner","input":{"attribute":"data-buy-input","contains":"Air Purifier","testid":"item-card"},"namedAction":{"args":[0,4,"never bought this"],"id":"submitReview","method":"POST","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"},{"in":"body","name":"rating"},{"in":"body","name":"comment"}],"path":"/api/items/:id/reviews","reducer":"submit_review"}},{"do":"expectActionOutcome","outcome":"application-refused","routeProvenBy":"owner"},{"do":"reload"},{"do":"ensureSignedIn","name":"uma"},{"do":"click","ifAvailable":true},{"do":"click","ifAvailable":true},{"do":"openItem","item":"Air Purifier"},{"contains":"eligible review control","do":"expect"},{"absent":true,"contains":"never bought this","do":"expect"}],"source":"scenarios/01-review-eligibility.json","stableKey":"ecommerce.spec.access-control.review-eligibility.108a","statedBy":"the server refuses a review from someone who has never ordered the item","withheld":null},{"category":"production","checkGroupId":"review-eligibility","criterionId":"108b","description":"buying the item earns the right to review it","featureId":108,"featureName":"A review is a claim about a purchase","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":1,"provenBy":null,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.reviews"],"role":"guarantee","semantics":[{"action":"buy","do":"callAction","input":{"attribute":"data-buy-input","contains":"Keyboard","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"}},{"do":"expectActionOutcome","outcome":"accepted"},{"do":"openItem","item":"Keyboard"},{"do":"click","ifAvailable":true,"unlessVisible":"review-rating"},{"do":"fill","text":"4"},{"do":"fill","text":"bought and used it"},{"do":"click"},{"contains":"bought and used it","do":"expect"}],"source":"scenarios/01-review-eligibility.json","stableKey":"ecommerce.spec.access-control.review-eligibility.108b","statedBy":"a customer can review an item they bought","withheld":null},{"category":"production","checkGroupId":"rating","criterionId":"6c","description":"the average rating reflects both reviewers and updates live","featureId":6,"featureName":"Reviews","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.live-state","points":1,"provenBy":null,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.reviews"],"role":"guarantee","semantics":[{"do":"openItem","item":"Gaming Mouse"},{"do":"click","ifAvailable":true,"unlessVisible":"review-rating"},{"do":"fill","text":"4"},{"do":"fill","text":"does the job"},{"do":"click"},{"do":"expectNumber","equals":3},{"do":"expectAgreement","numeric":true}],"source":"scenarios/01-review-rating-live.json","stableKey":"ecommerce.spec.live-state.rating.6c","statedBy":"each item shows its average rating, which updates live as reviews arrive","withheld":null},{"category":"production","checkGroupId":"unique-review","criterionId":"6b","description":"a later review submission does not create a duplicate for the same customer and item","featureId":6,"featureName":"Reviews","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.transactional-integrity","points":1,"provenBy":null,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.reviews"],"role":"guarantee","semantics":[{"do":"click","ifAvailable":true},{"do":"click","ifAvailable":true},{"action":"submitReview","do":"callAction","from":"author","input":{"attribute":"data-buy-input","contains":"Air Purifier","testid":"item-card"},"namedAction":{"args":[0,4,"changed my mind"],"id":"submitReview","method":"POST","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"},{"in":"body","name":"rating"},{"in":"body","name":"comment"}],"path":"/api/items/:id/reviews","reducer":"submit_review"}},{"do":"expectActionOutcome","outcome":"completed"},{"do":"reload"},{"do":"ensureSignedIn","name":"kira"},{"do":"click","ifAvailable":true},{"do":"click","ifAvailable":true},{"do":"openItem","item":"Air Purifier"},{"count":1,"do":"expect"}],"source":"scenarios/01-review-uniqueness.json","stableKey":"ecommerce.spec.transactional-integrity.unique-review.6b","statedBy":"one customer has at most one review per item","withheld":null},{"category":"feature","checkGroupId":"reviews","criterionId":"6a","description":"a customer can review an item and everyone sees it, signed out included","featureId":6,"featureName":"Reviews","note":null,"packId":"ecommerce.feature.reviews","points":2,"provenBy":null,"role":"feature","semantics":[{"do":"openItem","item":"Induction Cooktop"},{"do":"click","ifAvailable":true,"unlessVisible":"review-rating"},{"do":"fill","text":"4"},{"do":"fill","text":"solid mold"},{"do":"click"},{"contains":"solid mold","do":"expect"},{"do":"openItem","item":"Induction Cooktop"},{"contains":"solid mold","do":"expect"}],"source":"scenarios/01-review-visibility.json","stableKey":"ecommerce.feature.reviews.reviews.6a","statedBy":"reviews are visible to everyone, including signed-out visitors","withheld":null},{"category":"production","checkGroupId":"server-price","criterionId":"104a","description":"direct purchases of two differently priced items persist exactly one correctly priced order each","featureId":104,"featureName":"The price is the store's to set","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.transactional-integrity","points":2,"provenBy":null,"requiresFeatures":["ecommerce.feature.purchasing"],"role":"guarantee","semantics":[{"action":"buy","do":"callAction","input":{"attribute":"data-buy-input","contains":"Espresso Machine","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"}},{"do":"expectActionOutcome","outcome":"accepted"},{"action":"buy","do":"callAction","input":{"attribute":"data-buy-input","contains":"Coffee Grinder","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"}},{"do":"expectActionOutcome","outcome":"accepted"},{"do":"freshClient"},{"do":"signIn","name":"oli"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"count":2,"do":"expect"},{"contains":"Espresso Machine","count":1,"do":"expect"},{"do":"expectNumber","equals":449},{"contains":"Coffee Grinder","count":1,"do":"expect"},{"do":"expectNumber","equals":64}],"source":"scenarios/01-server-price.json","stableKey":"ecommerce.spec.transactional-integrity.server-price.104a","statedBy":"the server uses the current stored price when it creates an order","withheld":null},{"category":"production","checkGroupId":"warehouse-area-boundary","criterionId":"7a","description":"the administrator area stays unavailable to other staff","featureId":7,"featureName":"Admin and warehouses","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":1,"provenBy":null,"requiresFeatures":["ecommerce.feature.warehouse-admin"],"role":"guarantee","semantics":[{"do":"expect"},{"do":"click","ifAvailable":true},{"absent":true,"do":"expect"}],"source":"scenarios/01-warehouse-admin-staff.json","stableKey":"ecommerce.spec.access-control.warehouse-area-boundary.7a","statedBy":"Administrators can open the administration area; other staff cannot.","withheld":null},{"category":"feature","checkGroupId":"warehouse-view","criterionId":"7b","description":"admin lists every item, every warehouse, and what each warehouse holds","featureId":7,"featureName":"Admin and warehouses","note":null,"packId":"ecommerce.feature.warehouse-admin","points":1,"provenBy":null,"role":"feature","semantics":[{"count":13,"do":"expect"},{"count":26,"do":"expect"},{"contains":"East","do":"expect"},{"contains":"West","do":"expect"},{"do":"expectNumber","equals":100}],"source":"scenarios/01-warehouse-admin-staff.json","stableKey":"ecommerce.feature.warehouse-admin.warehouse-view.7b","statedBy":"admin lists every item with its stock, every warehouse, and the stock of each item in each warehouse","withheld":null},{"category":"production","checkGroupId":"warehouse-stock","criterionId":"7c","description":"the storefront stock is the sum across warehouses, and a restock raises it live","featureId":7,"featureName":"Warehouse stock stays live","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.live-state","points":2,"provenBy":null,"requiresFeatures":["ecommerce.feature.catalog-items","ecommerce.feature.warehouse-admin"],"role":"guarantee","semantics":[{"do":"fill","text":"25"},{"do":"click"},{"do":"expectNumber","equals":125},{"do":"expectNumber","equals":125}],"source":"scenarios/01-warehouse-stock-live-staff.json","stableKey":"ecommerce.spec.live-state.warehouse-stock.7c","statedBy":"an item's stock on the storefront is the sum of that item's units across all warehouses","withheld":null},{"category":"production","checkGroupId":"cancellation-and-return","criterionId":"3d","description":"cancelling a pending order removes it from the fulfilment queue","featureId":3,"featureName":"Cancellation and fulfilment","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.progression.cancellation-queue-specifications","points":1,"provenBy":null,"requiresFeatures":["ecommerce.l2.order-cancellation-features","ecommerce.progression.fulfilment-queue"],"role":"guarantee","semantics":[{"do":"click"},{"contains":"Coffee Grinder","do":"expect"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click"},{"do":"click"},{"do":"waitUntilAbsent"}],"source":"scenarios/02-cancellation-queue.json","stableKey":"ecommerce.returns-pricing.cancellation-and-return.3d","statedBy":"the order leaves the fulfilment queue","withheld":null},{"category":"production","checkGroupId":"fulfilment-area-boundary","criterionId":"1d","description":"staff and administrators can open fulfilment while customers cannot","featureId":1,"featureName":"Fulfilment area access","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":1,"provenBy":null,"requiresFeatures":["ecommerce.progression.fulfilment-queue"],"role":"guarantee","semantics":[{"do":"click"},{"do":"expect"},{"do":"click"},{"do":"expect"},{"do":"click","ifAvailable":true},{"absent":true,"do":"expect"}],"source":"scenarios/02-fulfilment-access.json","stableKey":"ecommerce.spec.access-control.fulfilment-area-boundary.1d","statedBy":"Customers cannot open the fulfilment area","withheld":null},{"category":"production","checkGroupId":"fulfilment-queue","criterionId":"1a","description":"an order placed by a customer appears in the staff queue without a reload","featureId":1,"featureName":"Live fulfilment queue","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.live-state","points":2,"provenBy":null,"requiresFeatures":["ecommerce.progression.fulfilment-queue"],"role":"guarantee","semantics":[{"as":"depth-before","do":"recordNumber"},{"do":"click"},{"contains":"Desk Lamp","do":"expect"},{"do":"expectNumber","plus":1,"relativeTo":"depth-before"}],"source":"scenarios/02-fulfilment-live.json","stableKey":"ecommerce.spec.live-state.fulfilment-queue.1a","statedBy":"New orders appear in the queue without a reload","withheld":null},{"category":"feature","checkGroupId":"fulfilment-queue","criterionId":"1c","description":"shipping removes the order from the queue and marks the customer's order shipped","featureId":1,"featureName":"Ship a pending order","note":null,"packId":"ecommerce.progression.fulfilment-queue","points":2,"provenBy":null,"requiresFeatures":["ecommerce.feature.purchasing"],"role":"feature","semantics":[{"action":"buy","do":"callAction","input":{"attribute":"data-buy-input","contains":"Keyboard","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"}},{"do":"expectActionOutcome","outcome":"accepted"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"do":"expect","ignoreCase":true,"value":"pending"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"do":"click","ifAvailable":true},{"contains":"Keyboard","do":"expect"},{"do":"click"},{"attribute":"data-submit-state","do":"expect","value":"succeeded"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"do":"click","ifAvailable":true},{"absent":true,"contains":"Keyboard","do":"expect"},{"do":"reload"},{"do":"ensureSignedIn","name":"fq-ship"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"do":"expect","ignoreCase":true,"value":"shipped"}],"source":"scenarios/02-fulfilment-ship.json","stableKey":"ecommerce.operations-access.fulfilment-queue.1c","statedBy":"Staff can mark an order as shipped; show the new status in the fulfilment area and the customer's order history.","withheld":null},{"category":"production","checkGroupId":"refund-accounting","criterionId":"203a","description":"concurrent cancellation restores original stock and the booked amount once, while revenue returns to its prior value","featureId":203,"featureName":"The books still balance once money can flow backwards","note":"Draft: native order, refund and original warehouse allocation evidence supplements the retained revenue assertions. Four calls from two sessions of the owner must cancel once; a repeated call may deliberately refuse or succeed without extra effects. Qualification pending.","observations":["requested","unmentioned"],"packId":"ecommerce.progression.cancellation-accounting-specifications","points":3,"provenBy":null,"requiresFeatures":["ecommerce.l2.order-cancellation-features"],"role":"guarantee","semantics":[{"as":"rev-start","do":"recordNumber"},{"do":"click"},{"do":"wait"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","ifAvailable":true},{"do":"click","unlessVisible":"admin-revenue"},{"do":"expectNumber","plus":42,"relativeTo":"rev-start"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"do":"expect","ignoreCase":true,"value":"pending"},{"account":"{user:books}","as":"cancel-before","do":"dbRecordCheckout","item":"Desk Lamp","storage":{"cart":false,"kind":"order-data","warehouses":true}},{"action":"cancel","do":"callConcurrently","from":"customer","input":{"attribute":"data-cancel-input","contains":"Desk Lamp","testid":"order-item"},"namedAction":{"args":[0],"id":"cancel","params":[{"in":"path","name":"orderId","placeholder":":id","wireType":"u64"}],"path":"/api/orders/:id/cancel","reducer":"cancel_order"},"requests":4},{"do":"expectCallOutcomes"},{"before":"cancel-before","do":"dbExpectCancellation"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","ifAvailable":true},{"do":"click","unlessVisible":"admin-revenue"},{"do":"expectNumber","plus":0,"relativeTo":"rev-start"}],"source":"scenarios/02-invariants.json","stableKey":"ecommerce.returns-pricing.refund-accounting.203a","statedBy":"revenue always equals the sum of orders that are still standing","withheld":null},{"category":"production","checkGroupId":"refund-accounting","criterionId":"203b","description":"a price change does not rewrite revenue already earned","featureId":203,"featureName":"The books still balance once money can flow backwards","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.progression.price-accounting-specifications","points":2,"provenBy":null,"requiresFeatures":["ecommerce.l2.price-history-features"],"role":"guarantee","semantics":[{"as":"history-revenue-before-sale","do":"recordNumber"},{"do":"pressKey","key":"Escape"},{"do":"click"},{"do":"wait"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","ifAvailable":true},{"do":"click","unlessVisible":"admin-revenue"},{"do":"expectNumber","plus":79.5,"relativeTo":"history-revenue-before-sale"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"contains":"Bluetooth Speaker","count":1,"do":"expect"},{"as":"rev-after-sale","do":"recordNumber"},{"do":"fill","text":"5.00"},{"do":"click"},{"do":"wait"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","ifAvailable":true},{"do":"expectNumber","equals":5},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","ifAvailable":true},{"do":"click","unlessVisible":"admin-revenue"},{"do":"expectNumber","plus":0,"relativeTo":"rev-after-sale"}],"source":"scenarios/02-invariants.json","stableKey":"ecommerce.returns-pricing.refund-accounting.203b","statedBy":"changing a price never alters the history, the revenue already recorded","withheld":null},{"category":"production","checkGroupId":"price-history","criterionId":"4b","description":"the new price reaches a signed-out visitor without a reload","featureId":4,"featureName":"Live catalog price","note":null,"packId":"ecommerce.l2.price-history-features","points":2,"provenBy":null,"role":"feature","semantics":[{"atLeast":2,"do":"expectNumber"},{"do":"fill","text":"1.00"},{"do":"click"},{"do":"expectNumber","equals":1}],"source":"scenarios/02-live-price.json","stableKey":"ecommerce.returns-pricing.price-history.4b","statedBy":"the storefront shows the new price immediately, to everyone","withheld":null},{"category":"feature","checkGroupId":"operational-views","criterionId":"5e","description":"the dashboard lists a current low-stock item","featureId":5,"featureName":"The low-stock view","note":null,"packId":"ecommerce.l2.inventory-dashboard","points":1,"provenBy":null,"role":"feature","semantics":[{"contains":"Air Purifier","do":"expect"}],"source":"scenarios/02-low-stock.json","stableKey":"ecommerce.inventory-operations.operational-views.5e","statedBy":"It lists items with 10 units or fewer, most urgent first.","withheld":null},{"category":"production","checkGroupId":"inventory-dashboard","criterionId":"5a","description":"an item falling to ten units or fewer joins the low-stock list, live","featureId":5,"featureName":"The low-stock view","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.live-state","points":3,"provenBy":null,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.l2.inventory-dashboard"],"role":"guarantee","semantics":[{"contains":"Air Purifier","do":"expect"},{"do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click"},{"do":"fill","text":"8"},{"do":"click"},{"do":"waitUntilAbsent"},{"do":"click"},{"contains":"Air Purifier","do":"expect"}],"source":"scenarios/02-low-stock.json","stableKey":"ecommerce.spec.live-state.inventory-dashboard.5a","statedBy":"items enter and leave this list as stock moves, sells, is restocked, cancelled or returned","withheld":null},{"category":"feature","checkGroupId":"operational-views","criterionId":"5d","description":"a signed-out visitor sees a best seller in the recommendations list","featureId":5,"featureName":"Signed-out best sellers","note":null,"packId":"ecommerce.l2.sales-dashboard","points":1,"provenBy":null,"role":"feature","semantics":[{"do":"reload"},{"do":"expectNumber","equals":1}],"source":"scenarios/02-operational-best-sellers.json","stableKey":"ecommerce.inventory-operations.operational-views.5d","statedBy":"Signed-out visitors see best sellers","withheld":null},{"category":"feature","checkGroupId":"operational-views","criterionId":"5f","description":"the dashboard shows category units and revenue","featureId":5,"featureName":"Category sales totals","note":null,"packId":"ecommerce.l2.sales-dashboard","points":1,"provenBy":null,"role":"feature","semantics":[{"do":"click","ifAvailable":true,"unlessVisible":"category-row"},{"as":"audio-core-units","do":"recordNumber"},{"as":"audio-core-revenue","do":"recordNumber"},{"do":"click"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click"},{"do":"click","ifAvailable":true,"unlessVisible":"category-row"},{"do":"expectNumber","plus":1,"relativeTo":"audio-core-units"},{"do":"expectNumber","plus":79.5,"relativeTo":"audio-core-revenue"}],"source":"scenarios/02-operational-category-totals.json","stableKey":"ecommerce.inventory-operations.operational-views.5f","statedBy":"Category totals show units sold and revenue for each category.","withheld":null},{"category":"production","checkGroupId":"sales-dashboard","criterionId":"5b","description":"a purchase updates that category's units and revenue live","featureId":5,"featureName":"Category sales totals","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.live-state","points":3,"provenBy":null,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.l2.sales-dashboard"],"role":"guarantee","semantics":[{"do":"click","ifAvailable":true,"unlessVisible":"category-row"},{"as":"audio-units","do":"recordNumber"},{"as":"audio-revenue","do":"recordNumber"},{"do":"click"},{"do":"expectNumber","plus":1,"relativeTo":"audio-units"},{"do":"expectNumber","plus":79.5,"relativeTo":"audio-revenue"}],"source":"scenarios/02-operational-category-totals.json","stableKey":"ecommerce.spec.live-state.sales-dashboard.5b","statedBy":"Category totals show units sold and revenue for each category","withheld":null},{"category":"feature","checkGroupId":"operational-views","criterionId":"5c","description":"a purchase recommends another item from that category and excludes an item in the cart","featureId":5,"featureName":"Customer recommendations","note":null,"packId":"ecommerce.l2.recommendations","points":2,"provenBy":null,"role":"feature","semantics":[{"do":"click"},{"do":"click","ifAvailable":true},{"do":"click","ifAvailable":true},{"contains":"Headphones","do":"expect"},{"do":"click"},{"do":"waitUntilAbsent"}],"source":"scenarios/02-operational-recommendations.json","stableKey":"ecommerce.inventory-operations.operational-views.5c","statedBy":"Recommend items from categories the customer bought from and exclude items already in the cart","withheld":null},{"category":"production","checkGroupId":"cancellation-and-return","criterionId":"3a","description":"cancelling a pending order restores its stock and revenue","featureId":3,"featureName":"Cancel a pending order","note":null,"packId":"ecommerce.l2.order-cancellation-features","points":2,"provenBy":null,"role":"feature","semantics":[{"as":"revenue-before","do":"recordNumber"},{"as":"stock-before","do":"recordNumber"},{"do":"click"},{"do":"expectNumber","plus":-1,"relativeTo":"stock-before"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","ifAvailable":true},{"do":"expectNumber","plus":64,"relativeTo":"revenue-before"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"do":"expect","ignoreCase":true,"value":"pending"},{"do":"click"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","ifAvailable":true},{"do":"expectNumber","plus":0,"relativeTo":"revenue-before"},{"do":"click","ifAvailable":true},{"do":"click","ifAvailable":true},{"do":"expectNumber","plus":0,"relativeTo":"stock-before"}],"source":"scenarios/02-order-cancellation-core.json","stableKey":"ecommerce.returns-pricing.cancellation-and-return.3a","statedBy":"the stock goes back to the warehouse it came from and revenue falls","withheld":null},{"category":"feature","checkGroupId":"cancellation-and-return","criterionId":"3b","description":"a cancelled order is shown as cancelled in the customer's history","featureId":3,"featureName":"Cancellation history","note":null,"packId":"ecommerce.l2.order-cancellation-features","points":1,"provenBy":null,"role":"feature","semantics":[{"do":"click"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"do":"click"},{"do":"expect","ignoreCase":true,"value":"cancelled"}],"source":"scenarios/02-order-cancellation-history.json","stableKey":"ecommerce.returns-pricing.cancellation-and-return.3b","statedBy":"a customer can cancel an order that has not shipped","withheld":null},{"category":"production","checkGroupId":"price-history","criterionId":"4a","description":"a price change updates the live catalog but leaves the customer's exact paid price unchanged","featureId":4,"featureName":"Prices change, history does not","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.progression.price-history-specifications","points":3,"provenBy":null,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.l2.price-history-features"],"role":"guarantee","semantics":[{"do":"fill","enter":true,"text":"Air Purifier"},{"as":"air-purifier-paid","do":"recordNumber"},{"do":"click"},{"do":"fill","enter":true,"text":"Air Purifier"},{"do":"fill","text":"1.00"},{"do":"click"},{"do":"expectNumber","equals":1},{"do":"reload"},{"do":"ensureSignedIn","name":"history-persisted"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click"},{"do":"expectNumber","plus":0,"relativeTo":"air-purifier-paid"}],"source":"scenarios/02-paid-price-history.json","stableKey":"ecommerce.returns-pricing.price-history.4a","statedBy":"past orders keep the price that was paid","withheld":null},{"category":"feature","checkGroupId":"fulfilment-queue","criterionId":"1b","description":"the queue names the warehouse the order will ship from","featureId":1,"featureName":"Fulfilment queue","note":null,"packId":"ecommerce.progression.fulfilment-queue","points":1,"provenBy":null,"role":"feature","semantics":[{"do":"dbSetStock","item":"Desk Lamp","quantity":0,"warehouse":"West"},{"do":"click"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"do":"click","ifAvailable":true},{"contains":"Desk Lamp","do":"expect"},{"contains":"East","do":"expect"}],"source":"scenarios/02-queue-warehouse.json","stableKey":"ecommerce.operations-access.fulfilment-queue.1b","statedBy":"which warehouse each will ship from","withheld":null},{"category":"production","checkGroupId":"stock-conservation","criterionId":"202b","description":"a sale and its cancellation leave the shelf exactly as they found it","featureId":202,"featureName":"Stock recovery is durable across clients","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.progression.inventory-conservation-specifications","points":2,"provenBy":null,"requiresFeatures":["ecommerce.l2.order-cancellation-features"],"role":"guarantee","semantics":[{"as":"east-before-cancel-202b","do":"dbRecordStock","item":"Induction Cooktop","warehouse":"East"},{"as":"west-before-cancel-202b","do":"dbRecordStock","item":"Induction Cooktop","warehouse":"West"},{"as":"stored-before-cancel-202b","do":"dbRecordStock","item":"Induction Cooktop"},{"as":"cancel-stock-before","do":"recordNumber"},{"do":"click"},{"do":"expectNumber","plus":-1,"relativeTo":"cancel-stock-before"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"contains":"Induction Cooktop","count":1,"do":"expect"},{"do":"dbExpectStock","item":"Induction Cooktop","plus":-1,"relativeTo":"stored-before-cancel-202b"},{"do":"click"},{"do":"click","ifAvailable":true},{"do":"click","ifAvailable":true},{"do":"expectNumber","plus":0,"relativeTo":"cancel-stock-before"},{"do":"dbExpectStock","item":"Induction Cooktop","plus":0,"relativeTo":"stored-before-cancel-202b"},{"do":"dbExpectStock","item":"Induction Cooktop","plus":0,"relativeTo":"east-before-cancel-202b","warehouse":"East"},{"do":"dbExpectStock","item":"Induction Cooktop","plus":0,"relativeTo":"west-before-cancel-202b","warehouse":"West"}],"source":"scenarios/02-self-contained.json","stableKey":"ecommerce.inventory-operations.stock-conservation.202b","statedBy":"the stock goes back to the warehouse it came from","withheld":null},{"category":"production","checkGroupId":"stock-conservation","criterionId":"202c","description":"a fresh client sees the restored total after a sale is cancelled","featureId":202,"featureName":"Stock recovery is durable across clients","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.progression.inventory-conservation-specifications","points":1,"provenBy":null,"requiresFeatures":["ecommerce.l2.order-cancellation-features"],"role":"guarantee","semantics":[{"as":"east-before-cancel-202c","do":"dbRecordStock","item":"Headphones","warehouse":"East"},{"as":"west-before-cancel-202c","do":"dbRecordStock","item":"Headphones","warehouse":"West"},{"as":"stored-before-cancel-202c","do":"dbRecordStock","item":"Headphones"},{"as":"fresh-stock-before","do":"recordNumber"},{"do":"click"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"contains":"Headphones","count":1,"do":"expect"},{"do":"dbExpectStock","item":"Headphones","plus":-1,"relativeTo":"stored-before-cancel-202c"},{"do":"click"},{"do":"freshClient"},{"do":"expectNumber","plus":0,"relativeTo":"fresh-stock-before"},{"do":"dbExpectStock","item":"Headphones","plus":0,"relativeTo":"stored-before-cancel-202c"},{"do":"dbExpectStock","item":"Headphones","plus":0,"relativeTo":"east-before-cancel-202c","warehouse":"East"},{"do":"dbExpectStock","item":"Headphones","plus":0,"relativeTo":"west-before-cancel-202c","warehouse":"West"}],"source":"scenarios/02-self-contained.json","stableKey":"ecommerce.inventory-operations.stock-conservation.202c","statedBy":"every one of these numbers is the same for every person looking at it","withheld":null},{"category":"production","checkGroupId":"operator-authorization","criterionId":"201c","description":"the server refuses a customer's direct attempt to ship their own pending order","featureId":201,"featureName":"Shipping requires an operator","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.progression.operations-access-specifications","points":2,"provenBy":null,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.progression.fulfilment-queue"],"role":"guarantee","semantics":[{"do":"click","ifAvailable":true},{"do":"click","ifAvailable":true},{"do":"click"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"contains":"Coffee Grinder","count":1,"do":"expect"},{"action":"ship","do":"callAction","from":"customer","input":{"attribute":"data-ship-input","contains":"Coffee Grinder","testid":"order-item"},"namedAction":{"args":[0],"id":"ship","params":[{"in":"body","name":"orderId","wireType":"u64"}],"path":"/api/fulfilment/ship","reducer":"ship_order"}},{"do":"expectActionOutcome","outcome":"accepted"},{"do":"reload"},{"do":"ensureSignedIn","name":"direct-notstaff"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"do":"expect","ignoreCase":true,"value":"shipped"},{"action":"ship","do":"callAction","input":{"attribute":"data-ship-input","contains":"Laptop Stand","testid":"order-item"},"namedAction":{"args":[0],"id":"ship","params":[{"in":"body","name":"orderId","wireType":"u64"}],"path":"/api/fulfilment/ship","reducer":"ship_order"}},{"do":"expectActionOutcome","outcome":"refused","routeProvenBy":"staff"},{"do":"reload"},{"do":"ensureSignedIn","name":"direct-notstaff"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"do":"expect","ignoreCase":true,"value":"pending"}],"source":"scenarios/02-server-actions.json","stableKey":"ecommerce.operations-access.operator-authorization.201c","statedBy":"Staff mark an order shipped","withheld":null},{"category":"production","checkGroupId":"stock-conservation","criterionId":"202d","description":"a direct transfer racing a direct purchase leaves the exact starting total minus the sold unit","featureId":202,"featureName":"Stock is conserved while operations overlap","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.progression.inventory-conservation-specifications","points":2,"provenBy":null,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.l2.stock-transfers-features"],"role":"guarantee","semantics":[{"do":"dbExpectStock","equals":60,"item":"Headphones","warehouse":"East"},{"do":"dbExpectStock","equals":40,"item":"Headphones","warehouse":"West"},{"as":"direct-race-stock-before","do":"dbRecordStock","item":"Headphones"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","ifAvailable":true},{"do":"reload"},{"do":"ensureSignedIn","name":"direct-conserve"},{"do":"fill","text":"East"},{"do":"fill","text":"West"},{"do":"fill","text":"25"},{"branches":[[{"action":"transfer","do":"callAction","input":{"attribute":"data-transfer-input","contains":"Headphones","testid":"admin-item-row"},"namedAction":{"args":[0,0,0,25],"id":"transfer","params":[{"in":"body","name":"itemId","wireType":"u64"},{"in":"body","name":"fromWarehouseId","wireType":"u64"},{"in":"body","name":"toWarehouseId","wireType":"u64"},{"in":"body","name":"quantity"}],"path":"/api/admin/transfer","reducer":"admin_transfer_stock"}}],[{"action":"buy","do":"callAction","input":{"attribute":"data-buy-input","contains":"Headphones","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"}}]],"do":"race"},{"do":"expectActionOutcome","outcome":"accepted"},{"do":"expectActionOutcome","outcome":"accepted"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","ifAvailable":true},{"do":"expectNumber","plus":-1,"relativeTo":"direct-race-stock-before"},{"do":"reload"},{"do":"ensureSignedIn","name":"direct-conserve"},{"do":"click","ifAvailable":true},{"do":"click","ifAvailable":true},{"do":"expectNumber","plus":-1,"relativeTo":"direct-race-stock-before"},{"atLeast":34,"atMost":35,"do":"dbExpectStock","item":"Headphones","warehouse":"East"},{"atLeast":64,"atMost":65,"do":"dbExpectStock","item":"Headphones","warehouse":"West"},{"do":"dbExpectStock","item":"Headphones","plus":-1,"relativeTo":"direct-race-stock-before"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"contains":"Headphones","count":1,"do":"expect"}],"source":"scenarios/02-server-actions.json","stableKey":"ecommerce.inventory-operations.stock-conservation.202d","statedBy":"a transfer moves stock, it does not create or destroy it","withheld":null},{"category":"production","checkGroupId":"order-owner","criterionId":"204a","description":"the server refuses one customer trying to cancel another customer's still-pending order","featureId":204,"featureName":"An order belongs to the person who placed it","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.progression.operations-access-specifications","points":2,"provenBy":null,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.l2.order-cancellation-features"],"role":"guarantee","semantics":[{"action":"cancel","do":"callAction","input":{"attribute":"data-cancel-input","contains":"Desk Lamp","testid":"order-item"},"namedAction":{"args":[0],"id":"cancel","params":[{"in":"path","name":"orderId","placeholder":":id","wireType":"u64"}],"path":"/api/orders/:id/cancel","reducer":"cancel_order"}},{"do":"expectActionOutcome","outcome":"accepted"},{"action":"cancel","do":"callAction","from":"owner","input":{"attribute":"data-cancel-input","contains":"Keyboard","testid":"order-item"},"namedAction":{"args":[0],"id":"cancel","params":[{"in":"path","name":"orderId","placeholder":":id","wireType":"u64"}],"path":"/api/orders/:id/cancel","reducer":"cancel_order"}},{"do":"expectActionOutcome","outcome":"refused","routeProvenBy":"owner"},{"do":"reload"},{"do":"ensureSignedIn","name":"direct-owner"},{"do":"click","ifAvailable":true},{"do":"click","unlessVisible":"order-item"},{"do":"expect","ignoreCase":true,"value":"pending"}],"source":"scenarios/02-server-actions.json","stableKey":"ecommerce.operations-access.order-owner.204a","statedBy":"A customer can cancel an order that has not shipped","withheld":null},{"category":"production","checkGroupId":"warehouse-transfer","criterionId":"2a","description":"a transfer decreases the source, increases the destination, and preserves the item's exact total","featureId":2,"featureName":"Moving stock between warehouses","note":null,"packId":"ecommerce.l2.stock-transfers-features","points":3,"provenBy":null,"role":"feature","semantics":[{"as":"product-East","do":"dbRecordStock","item":"Headphones","warehouse":"East"},{"as":"product-West","do":"dbRecordStock","item":"Headphones","warehouse":"West"},{"as":"transfer-item-before","do":"recordNumber"},{"contains":"East","count":1,"do":"expect"},{"as":"transfer-east-before","do":"recordNumber"},{"contains":"West","count":1,"do":"expect"},{"as":"transfer-west-before","do":"recordNumber"},{"do":"fill","text":"East"},{"do":"fill","text":"West"},{"do":"fill","text":"10"},{"do":"click"},{"contains":"East","count":1,"do":"expect"},{"do":"dbExpectStock","item":"Headphones","plus":-10,"relativeTo":"product-East","warehouse":"East"},{"do":"dbExpectStock","item":"Headphones","plus":10,"relativeTo":"product-West","warehouse":"West"},{"do":"expectNumber","plus":-10,"relativeTo":"transfer-east-before"},{"contains":"West","count":1,"do":"expect"},{"do":"expectNumber","plus":10,"relativeTo":"transfer-west-before"},{"do":"expectNumber","plus":0,"relativeTo":"transfer-item-before"}],"source":"scenarios/02-strengthened.json","stableKey":"ecommerce.inventory-operations.warehouse-transfer.2a","statedBy":"a transfer moves stock, it does not create or destroy it","withheld":null},{"category":"production","checkGroupId":"operator-authorization","criterionId":"201a","description":"the server refuses a customer's direct transfer and neither warehouse nor the item total changes","featureId":201,"featureName":"Operating the store requires authorization","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.progression.operations-access-specifications","points":2,"provenBy":null,"requiresFeatures":["ecommerce.l2.stock-transfers-features"],"role":"guarantee","semantics":[{"as":"authorized-transfer-east","do":"dbRecordStock","item":"Headphones","warehouse":"East"},{"as":"authorized-transfer-west","do":"dbRecordStock","item":"Headphones","warehouse":"West"},{"do":"fill","text":"East"},{"do":"fill","text":"West"},{"do":"fill","text":"25"},{"action":"transfer","do":"callAction","input":{"attribute":"data-transfer-input","contains":"Headphones","testid":"admin-item-row"},"namedAction":{"args":[0,0,0,25],"id":"transfer","params":[{"in":"body","name":"itemId","wireType":"u64"},{"in":"body","name":"fromWarehouseId","wireType":"u64"},{"in":"body","name":"toWarehouseId","wireType":"u64"},{"in":"body","name":"quantity"}],"path":"/api/admin/transfer","reducer":"admin_transfer_stock"}},{"do":"expectActionOutcome","outcome":"accepted"},{"do":"dbExpectStock","item":"Headphones","plus":-25,"relativeTo":"authorized-transfer-east","warehouse":"East"},{"do":"dbExpectStock","item":"Headphones","plus":25,"relativeTo":"authorized-transfer-west","warehouse":"West"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","ifAvailable":true},{"do":"reload"},{"do":"ensureSignedIn","name":"not-operator"},{"as":"unauthorized-item-before","do":"recordNumber"},{"contains":"East","count":1,"do":"expect"},{"as":"unauthorized-east-before","do":"recordNumber"},{"contains":"West","count":1,"do":"expect"},{"as":"unauthorized-west-before","do":"recordNumber"},{"do":"fill","text":"East"},{"do":"fill","text":"West"},{"as":"refused-East","do":"dbRecordStock","item":"Headphones","warehouse":"East"},{"as":"refused-West","do":"dbRecordStock","item":"Headphones","warehouse":"West"},{"action":"transfer","do":"callAction","from":"admin","input":{"attribute":"data-transfer-input","contains":"Headphones","testid":"admin-item-row"},"namedAction":{"args":[0,0,0,25],"id":"transfer","params":[{"in":"body","name":"itemId","wireType":"u64"},{"in":"body","name":"fromWarehouseId","wireType":"u64"},{"in":"body","name":"toWarehouseId","wireType":"u64"},{"in":"body","name":"quantity"}],"path":"/api/admin/transfer","reducer":"admin_transfer_stock"}},{"do":"expectActionOutcome","outcome":"refused","routeProvenBy":"admin"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","ifAvailable":true},{"do":"reload"},{"do":"ensureSignedIn","name":"not-operator"},{"contains":"East","count":1,"do":"expect"},{"do":"dbExpectStock","item":"Headphones","plus":0,"relativeTo":"refused-East","warehouse":"East"},{"do":"dbExpectStock","item":"Headphones","plus":0,"relativeTo":"refused-West","warehouse":"West"},{"do":"expectNumber","plus":0,"relativeTo":"unauthorized-east-before"},{"contains":"West","count":1,"do":"expect"},{"do":"expectNumber","plus":0,"relativeTo":"unauthorized-west-before"},{"do":"expectNumber","plus":0,"relativeTo":"unauthorized-item-before"}],"source":"scenarios/02-strengthened.json","stableKey":"ecommerce.operations-access.operator-authorization.201a","statedBy":"An admin can transfer a number of units of an item from one warehouse to another","withheld":null},{"category":"production","checkGroupId":"operator-authorization","criterionId":"201b","description":"the server refuses a customer's direct price change and the last accepted price remains exact","featureId":201,"featureName":"Operating the store requires authorization","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.progression.operations-access-specifications","points":2,"provenBy":null,"requiresFeatures":["ecommerce.l2.price-history-features"],"role":"guarantee","semantics":[{"do":"fill","text":"77.00"},{"action":"price","do":"callAction","input":{"attribute":"data-price-input","contains":"Gaming Mouse","testid":"admin-item-row"},"namedAction":{"args":[0,1],"id":"price","params":[{"in":"body","name":"itemId","wireType":"u64"},{"in":"body","name":"price"}],"path":"/api/admin/price","reducer":"admin_change_price"}},{"do":"expectActionOutcome","outcome":"accepted"},{"do":"reload"},{"do":"ensureSignedIn","name":"not-operator"},{"do":"expectNumber","equals":77},{"do":"fill","text":"1.00"},{"action":"price","do":"callAction","from":"admin","input":{"attribute":"data-price-input","contains":"Gaming Mouse","testid":"admin-item-row"},"namedAction":{"args":[0,1],"id":"price","params":[{"in":"body","name":"itemId","wireType":"u64"},{"in":"body","name":"price"}],"path":"/api/admin/price","reducer":"admin_change_price"}},{"do":"expectActionOutcome","outcome":"refused","routeProvenBy":"admin"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","ifAvailable":true},{"do":"reload"},{"do":"ensureSignedIn","name":"not-operator"},{"do":"expectNumber","equals":77}],"source":"scenarios/02-strengthened.json","stableKey":"ecommerce.operations-access.operator-authorization.201b","statedBy":"an admin can change an item's price","withheld":null},{"category":"production","checkGroupId":"stock-conservation","criterionId":"202a","description":"a transfer decreases East, increases West, and leaves the item's exact total unchanged","featureId":202,"featureName":"Stock is conserved however it moves","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.progression.inventory-conservation-specifications","points":2,"provenBy":null,"requiresFeatures":["ecommerce.l2.stock-transfers-features"],"role":"guarantee","semantics":[{"as":"product-East","do":"dbRecordStock","item":"Espresso Machine","warehouse":"East"},{"as":"product-West","do":"dbRecordStock","item":"Espresso Machine","warehouse":"West"},{"as":"conservation-item-before","do":"recordNumber"},{"contains":"East","count":1,"do":"expect"},{"as":"conservation-east-before","do":"recordNumber"},{"contains":"West","count":1,"do":"expect"},{"as":"conservation-west-before","do":"recordNumber"},{"do":"fill","text":"East"},{"do":"fill","text":"West"},{"do":"fill","text":"17"},{"do":"click"},{"contains":"East","count":1,"do":"expect"},{"do":"dbExpectStock","item":"Espresso Machine","plus":-17,"relativeTo":"product-East","warehouse":"East"},{"do":"dbExpectStock","item":"Espresso Machine","plus":17,"relativeTo":"product-West","warehouse":"West"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","unlessVisible":"admin-revenue"},{"do":"expectNumber","plus":-17,"relativeTo":"conservation-east-before"},{"contains":"West","count":1,"do":"expect"},{"do":"expectNumber","plus":17,"relativeTo":"conservation-west-before"},{"do":"expectNumber","plus":0,"relativeTo":"conservation-item-before"}],"source":"scenarios/02-strengthened.json","stableKey":"ecommerce.inventory-operations.stock-conservation.202a","statedBy":"a transfer moves stock, it does not create or destroy it","withheld":null},{"category":"production","checkGroupId":"stock-transfer-overdraw","criterionId":"2c","description":"a transfer that would overdraw a warehouse is refused and changes neither warehouse nor the item total","featureId":2,"featureName":"Moving stock between warehouses","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.transactional-integrity","points":2,"provenBy":null,"requiresFeatures":["ecommerce.l2.stock-transfers-features"],"role":"guarantee","semantics":[{"as":"product-East","do":"dbRecordStock","item":"Headphones","warehouse":"East"},{"as":"product-West","do":"dbRecordStock","item":"Headphones","warehouse":"West"},{"as":"overdraw-item-before","do":"recordNumber"},{"as":"overdraw-east-before","do":"recordNumber"},{"as":"overdraw-west-before","do":"recordNumber"},{"do":"fill","text":"East"},{"do":"fill","text":"West"},{"do":"fill","text":"99999"},{"do":"click"},{"do":"expect"},{"do":"dbExpectStock","item":"Headphones","plus":0,"relativeTo":"product-East","warehouse":"East"},{"do":"dbExpectStock","item":"Headphones","plus":0,"relativeTo":"product-West","warehouse":"West"},{"do":"expectNumber","plus":0,"relativeTo":"overdraw-east-before"},{"do":"expectNumber","plus":0,"relativeTo":"overdraw-west-before"},{"do":"expectNumber","plus":0,"relativeTo":"overdraw-item-before"}],"source":"scenarios/02-transfer-overdraw.json","stableKey":"ecommerce.spec.transactional-integrity.stock-transfer-overdraw.2c","statedBy":"a transfer that would leave a warehouse short is refused and changes nothing","withheld":null},{"category":"production","checkGroupId":"stock-transfers","criterionId":"2b","description":"both warehouse totals move live and in opposite directions as stock is transferred","featureId":2,"featureName":"Warehouse totals","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.live-state","points":2,"provenBy":null,"requiresFeatures":["ecommerce.l2.stock-transfers-features"],"role":"guarantee","semantics":[{"as":"product-East","do":"dbRecordStock","item":"Headphones","warehouse":"East"},{"as":"product-West","do":"dbRecordStock","item":"Headphones","warehouse":"West"},{"contains":"East","count":1,"do":"expect"},{"as":"warehouse-east-before","do":"recordNumber"},{"contains":"West","count":1,"do":"expect"},{"as":"warehouse-west-before","do":"recordNumber"},{"do":"fill","text":"East"},{"do":"fill","text":"West"},{"do":"fill","text":"10"},{"do":"click"},{"contains":"East","count":1,"do":"expect"},{"do":"expectNumber","plus":-10,"relativeTo":"warehouse-east-before"},{"contains":"West","count":1,"do":"expect"},{"do":"expectNumber","plus":10,"relativeTo":"warehouse-west-before"},{"do":"dbExpectStock","item":"Headphones","plus":-10,"relativeTo":"product-East","warehouse":"East"},{"do":"dbExpectStock","item":"Headphones","plus":10,"relativeTo":"product-West","warehouse":"West"}],"source":"scenarios/02-transfer-totals.json","stableKey":"ecommerce.spec.live-state.stock-transfers.2b","statedBy":"the per-warehouse numbers staff and admins see both move at once","withheld":null},{"category":"production","checkGroupId":"cart-expiration","criterionId":"304a","description":"an inactive cart expires without a browser, releases stock, and returns empty","featureId":304,"featureName":"An inactive cart expires","note":null,"packId":"ecommerce.l3.cart-expiration-features","points":4,"provenBy":null,"role":"feature","semantics":[{"do":"wait"},{"do":"reload"},{"do":"expectNumber","plus":0,"relativeTo":"before"},{"do":"openClient"},{"do":"expect"},{"do":"expectNumber","equals":0}],"source":"scenarios/03-cart-expiration.json","stableKey":"ecommerce.l3.cart-expiration.cart-expiration.304a","statedBy":"A cart with no activity for five minutes expires and releases its reservations.","withheld":null},{"category":"production","checkGroupId":"scheduled-work-access","criterionId":"317a","description":"the server refuses customer scheduling and cancellation of restocks","featureId":317,"featureName":"Customers cannot manage scheduled restocks","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.l3.deferred-access-specifications","points":3,"provenBy":null,"requiresFeatures":["ecommerce.l3.scheduled-restocks-features"],"role":"guarantee","semantics":[{"do":"fill","text":"Webcam"},{"do":"fill","text":"West"},{"do":"fill","text":"3"},{"do":"fill","text":"180"},{"action":"scheduleRestock","authentication":"actor","do":"callAction","from":"admin","input":{"attribute":"data-action-input","testid":"schedule-restock-submit"},"namedAction":{"args":["","",0,0],"id":"scheduleRestock","method":"POST","params":[{"in":"body","name":"item"},{"in":"body","name":"warehouse"},{"in":"body","name":"quantity"},{"in":"body","name":"delaySeconds"}],"path":"/api/admin/scheduled-restocks","reducer":"schedule_restock"}},{"do":"expectActionOutcome","outcome":"refused"},{"do":"replayAs","from":"admin","match":"DELETE","namedAction":{"args":[0],"id":"cancelScheduledRestock","method":"DELETE","params":[{"in":"path","name":"restockId","placeholder":"{restockId}","wireType":"u64"}],"path":"/api/admin/scheduled-restocks/{restockId}","reducer":"cancel_scheduled_restock"},"namedTarget":{"attribute":"data-entity-id","testid":"pending-restock-item","valueType":"string"}},{"do":"expectReplayRejected"},{"count":1,"do":"expect"},{"do":"click"}],"source":"scenarios/03-deferred-access.json","stableKey":"ecommerce.l3.deferred-access.scheduled-work-access.317a","statedBy":"Only an admin can schedule or cancel a restock.","withheld":null},{"category":"production","checkGroupId":"restart-survival","criterionId":"311a","description":"a restock scheduled before restart still applies","featureId":311,"featureName":"A scheduled restock survives restart","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.l3.deferred-durability-specifications","points":4,"provenBy":null,"requiresFeatures":["ecommerce.l3.scheduled-restocks-features"],"role":"guarantee","semantics":[{"do":"dbExpectStock","item":"Air Purifier","plus":5,"relativeTo":"before"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","ifAvailable":true},{"do":"click","ifAvailable":true},{"do":"expect"},{"absent":true,"do":"expect"}],"source":"scenarios/03-deferred-durability.json","stableKey":"ecommerce.l3.deferred-durability.restart-survival.311a","statedBy":"Pending restocks survive a backend restart.","withheld":null},{"category":"production","checkGroupId":"restart-survival","criterionId":"314a","description":"a reservation pending before restart still expires and returns stock","featureId":314,"featureName":"A reservation survives restart","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.l3.deferred-durability-specifications","points":4,"provenBy":null,"requiresFeatures":["ecommerce.l3.reservations-features"],"role":"guarantee","semantics":[{"atMost":70000,"do":"expectElapsed","since":"pending-314"},{"do":"reload"},{"atMost":70000,"do":"expectElapsed","since":"pending-314"},{"do":"expectNumber","plus":-1,"relativeTo":"before"},{"atMost":70000,"do":"expectElapsed","since":"pending-314"},{"do":"wait","since":"pending-314-accepted"},{"do":"reload"},{"do":"expectNumber","plus":0,"relativeTo":"before"},{"do":"reload"},{"do":"ensureSignedIn","name":"durable-reservation"},{"do":"click","unlessVisible":"cart-item"},{"do":"expect"}],"source":"scenarios/03-deferred-durability.json","stableKey":"ecommerce.l3.deferred-durability.restart-survival.314a","statedBy":"Pending reservations survive a backend restart.","withheld":null},{"category":"production","checkGroupId":"restart-survival","criterionId":"315a","description":"an order shipped before restart still becomes delivered","featureId":315,"featureName":"An order transition survives restart","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.l3.deferred-durability-specifications","points":4,"provenBy":null,"requiresFeatures":["ecommerce.l3.order-delivery-features"],"role":"guarantee","semantics":[{"do":"wait","since":"delivery-start-accepted"},{"do":"reload"},{"do":"ensureSignedIn","name":"durable-delivery"},{"do":"click","ifAvailable":true},{"do":"click","unlessVisible":"order-item"},{"do":"expect","ignoreCase":true,"value":"delivered"}],"source":"scenarios/03-deferred-durability.json","stableKey":"ecommerce.l3.deferred-durability.restart-survival.315a","statedBy":"Pending order delivery survives a backend restart.","withheld":null},{"category":"production","checkGroupId":"restart-survival","criterionId":"316a","description":"a cart survives restart and expires near its original five-minute deadline","featureId":316,"featureName":"Cart expiration survives restart","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.l3.deferred-durability-specifications","points":4,"provenBy":null,"requiresFeatures":["ecommerce.l3.cart-expiration-features"],"role":"guarantee","semantics":[{"atMost":250000,"do":"expectElapsed","since":"pending-316"},{"do":"reload"},{"do":"ensureSignedIn","name":"durable-cart"},{"do":"click","ifAvailable":true},{"do":"click","unlessVisible":"cart-item"},{"atMost":250000,"do":"expectElapsed","since":"pending-316"},{"do":"expectNumber","equals":1},{"atMost":250000,"do":"expectElapsed","since":"pending-316"},{"do":"wait","since":"pending-316-accepted"},{"do":"reload"},{"do":"ensureSignedIn","name":"durable-cart"},{"do":"click"},{"do":"expectNumber","equals":0},{"do":"expect"},{"do":"reload"},{"do":"expectNumber","plus":0,"relativeTo":"before"}],"source":"scenarios/03-deferred-durability.json","stableKey":"ecommerce.l3.deferred-durability.restart-survival.316a","statedBy":"Pending cart expiration survives a backend restart.","withheld":null},{"category":"production","checkGroupId":"exactly-once","criterionId":"311a","description":"restart cannot replay a completed restock","featureId":311,"featureName":"A restock applies once","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.l3.deferred-integrity-specifications","points":3,"provenBy":null,"requiresFeatures":["ecommerce.l3.scheduled-restocks-features"],"role":"guarantee","semantics":[{"do":"reload"},{"do":"dbExpectStock","item":"Air Purifier","plus":5,"relativeTo":"before"},{"do":"restartBackend"},{"do":"reload"},{"do":"wait"},{"do":"dbExpectStock","item":"Air Purifier","plus":5,"relativeTo":"before"}],"source":"scenarios/03-deferred-integrity.json","stableKey":"ecommerce.l3.deferred-integrity.exactly-once.311a","statedBy":"Restarting the backend cannot apply a restock more than once.","withheld":null},{"category":"production","checkGroupId":"exactly-once","criterionId":"312a","description":"restart leaves one delivered order record","featureId":312,"featureName":"Delivery applies once","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.l3.deferred-integrity-specifications","points":3,"provenBy":null,"requiresFeatures":["ecommerce.l3.order-delivery-features"],"role":"guarantee","semantics":[{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"do":"click","ifAvailable":true},{"contains":"Desk Lamp","count":1,"do":"expect"},{"do":"expect","ignoreCase":true,"value":"delivered"}],"source":"scenarios/03-deferred-integrity.json","stableKey":"ecommerce.l3.deferred-integrity.exactly-once.312a","statedBy":"A delivered order is not duplicated by a backend restart.","withheld":null},{"category":"production","checkGroupId":"stock-conservation","criterionId":"313a","description":"expiry returns exactly the unit reserved","featureId":313,"featureName":"Reservation expiry conserves stock","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.l3.deferred-integrity-specifications","points":3,"provenBy":null,"requiresFeatures":["ecommerce.l3.reservations-features"],"role":"guarantee","semantics":[{"do":"wait"},{"do":"reload"},{"do":"expectNumber","plus":0,"relativeTo":"before"}],"source":"scenarios/03-deferred-integrity.json","stableKey":"ecommerce.l3.deferred-integrity.stock-conservation.313a","statedBy":"Reservation expiry returns exactly the stock that the reservation took.","withheld":null},{"category":"production","checkGroupId":"stock-conservation","criterionId":"314a","description":"checkout does not decrement stock after the reservation already did","featureId":314,"featureName":"Checkout conserves reserved stock","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.l3.deferred-integrity-specifications","points":3,"provenBy":null,"requiresFeatures":["ecommerce.l3.reservations-features"],"role":"guarantee","semantics":[{"do":"click"},{"do":"expectNumber","equals":0},{"do":"reload"},{"do":"ensureSignedIn","name":"conserve-checkout"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click"},{"contains":"Headphones","do":"expectElementCount","equals":1},{"do":"reload"},{"do":"expectNumber","plus":-1,"relativeTo":"before"}],"source":"scenarios/03-deferred-integrity.json","stableKey":"ecommerce.l3.deferred-integrity.stock-conservation.314a","statedBy":"Checkout does not take reserved stock twice.","withheld":null},{"category":"production","checkGroupId":"order-delivery","criterionId":"303a","description":"a shipped order becomes delivered in customer and staff views","featureId":303,"featureName":"A shipped order becomes delivered","note":null,"packId":"ecommerce.l3.order-delivery-features","points":3,"provenBy":null,"role":"feature","semantics":[{"do":"wait"},{"do":"reload"},{"do":"ensureSignedIn","name":"delivery-live"},{"do":"click","ifAvailable":true},{"do":"click","unlessVisible":"order-item"},{"do":"expect","ignoreCase":true,"value":"delivered"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"do":"click","ifAvailable":true},{"do":"click","unlessVisible":"completed-order-item"},{"do":"expect","ignoreCase":true,"value":"delivered"}],"source":"scenarios/03-order-delivery.json","stableKey":"ecommerce.l3.order-delivery.order-delivery.303a","statedBy":"A shipped order becomes delivered after 60 seconds.","withheld":null},{"category":"production","checkGroupId":"order-delivery","criterionId":"305a","description":"a cancelled order remains cancelled after the delivery interval","featureId":305,"featureName":"Cancellation is final","note":null,"packId":"ecommerce.l3.order-delivery-features","points":2,"provenBy":null,"role":"feature","semantics":[{"do":"wait"},{"do":"reload"},{"do":"ensureSignedIn","name":"delivery-cancel"},{"do":"click","ifAvailable":true},{"do":"click","unlessVisible":"order-item"},{"do":"expect","ignoreCase":true,"value":"cancelled"}],"source":"scenarios/03-order-delivery.json","stableKey":"ecommerce.l3.order-delivery.order-delivery.305a","statedBy":"A cancelled order never advances.","withheld":null},{"category":"production","checkGroupId":"reservations","criterionId":"301a","description":"adding an item reserves one unit for every open viewer","featureId":301,"featureName":"A cart reserves stock","note":null,"packId":"ecommerce.l3.reservations-features","points":2,"provenBy":null,"role":"feature","semantics":[{"do":"click"},{"do":"expectNumber","plus":-1,"relativeTo":"before"}],"source":"scenarios/03-reservations.json","stableKey":"ecommerce.l3.reservations.reservations.301a","statedBy":"Adding an item to a cart reserves its stock immediately for 90 seconds.","withheld":null},{"category":"interface","checkGroupId":"reservations","criterionId":"305a","description":"the reservation timer decreases","featureId":305,"featureName":"Reservation time is visible","note":null,"packId":"ecommerce.l3.reservations-features","points":1,"provenBy":null,"role":"feature","semantics":[{"atLeast":1,"atMost":90,"do":"expectNumber"},{"as":"initial-countdown","do":"recordNumber"},{"do":"wait"},{"comparison":"atMost","do":"expectNumber","plus":-1,"relativeTo":"initial-countdown"}],"source":"scenarios/03-reservations.json","stableKey":"ecommerce.l3.reservations.reservations.305a","statedBy":"The cart shows the remaining reservation time.","withheld":null},{"category":"feature","checkGroupId":"reservations","criterionId":"306a","description":"checkout converts the reservation into an order and empties the cart","featureId":306,"featureName":"Checkout consumes a reservation","note":null,"packId":"ecommerce.l3.reservations-features","points":2,"provenBy":null,"role":"feature","semantics":[{"do":"click"},{"do":"expectNumber","equals":0},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click"},{"contains":"Keyboard","count":1,"do":"expect"}],"source":"scenarios/03-reservations.json","stableKey":"ecommerce.l3.reservations.reservations.306a","statedBy":"Checkout converts a live reservation into a sale.","withheld":null},{"category":"feature","checkGroupId":"reservations","criterionId":"307a","description":"an expired reservation marks its cart line","featureId":307,"featureName":"A reservation expires","note":null,"packId":"ecommerce.l3.reservations-features","points":3,"provenBy":null,"role":"feature","semantics":[{"do":"wait"},{"do":"expect"}],"source":"scenarios/03-reservations.json","stableKey":"ecommerce.l3.reservations.reservations.307a","statedBy":"An expired reservation remains visible as expired.","withheld":null},{"category":"feature","checkGroupId":"reservations","criterionId":"308a","description":"raising quantity starts a new reservation window","featureId":308,"featureName":"Changing quantity renews a reservation","note":null,"packId":"ecommerce.l3.reservations-features","points":2,"provenBy":null,"role":"feature","semantics":[{"do":"wait"},{"atLeast":35,"do":"expectNumber"},{"absent":true,"do":"expect"}],"source":"scenarios/03-reservations.json","stableKey":"ecommerce.l3.reservations.reservations.308a","statedBy":"Adding the item again renews the reservation.","withheld":null},{"category":"feature","checkGroupId":"scheduled-restocks","criterionId":"305a","description":"a due restock updates stock and moves to the ledger","featureId":305,"featureName":"A due restock applies","note":null,"packId":"ecommerce.l3.scheduled-restocks-features","points":3,"provenBy":null,"role":"feature","semantics":[{"as":"ledger-before","count":true,"do":"recordNumber"},{"do":"fill","text":"Keyboard"},{"do":"fill","text":"West"},{"do":"fill","text":"7"},{"do":"fill","text":"15"},{"do":"click"},{"do":"wait"},{"do":"reload"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","ifAvailable":true},{"do":"click","ifAvailable":true},{"do":"expectNumber","plus":7,"relativeTo":"before"},{"absent":true,"do":"expect"},{"do":"expectElementCount","plus":1,"relativeTo":"ledger-before"}],"source":"scenarios/03-scheduled-restock-apply.json","stableKey":"ecommerce.l3.scheduled-restocks.scheduled-restocks.305a","statedBy":"A due restock updates stock, leaves the pending list, and enters the stock ledger.","withheld":null},{"category":"production","checkGroupId":"scheduled-restocks","criterionId":"306a","description":"a cancelled restock never applies","featureId":306,"featureName":"A scheduled restock can be cancelled","note":null,"packId":"ecommerce.l3.scheduled-restocks-features","points":2,"provenBy":null,"role":"feature","semantics":[{"do":"fill","text":"Desk Lamp"},{"do":"fill","text":"East"},{"do":"fill","text":"9"},{"do":"fill","text":"15"},{"do":"click"},{"count":1,"do":"expect"},{"do":"click"},{"do":"wait"},{"do":"reload"},{"do":"expectNumber","plus":0,"relativeTo":"before"}],"source":"scenarios/03-scheduled-restock-cancel.json","stableKey":"ecommerce.l3.scheduled-restocks.scheduled-restocks.306a","statedBy":"An admin can schedule and cancel a restock.","withheld":null},{"category":"feature","checkGroupId":"scheduled-restocks","criterionId":"302a","description":"a scheduled restock is pending and its remaining time decreases","featureId":302,"featureName":"A restock is pending before it is due","note":null,"packId":"ecommerce.l3.scheduled-restocks-features","points":2,"provenBy":null,"role":"feature","semantics":[{"do":"fill","text":"Webcam"},{"do":"fill","text":"East"},{"do":"fill","text":"7"},{"do":"fill","text":"90"},{"do":"click"},{"count":1,"do":"expect"},{"atLeast":1,"atMost":90,"do":"expectNumber"},{"as":"initial-countdown","do":"recordNumber"},{"do":"wait"},{"comparison":"atMost","do":"expectNumber","plus":-1,"relativeTo":"initial-countdown"},{"do":"click"}],"source":"scenarios/03-scheduled-restocks.json","stableKey":"ecommerce.l3.scheduled-restocks.scheduled-restocks.302a","statedBy":"A pending restock shows its remaining time.","withheld":null},{"category":"production","checkGroupId":"server-time","criterionId":"312a","description":"restart preserves the due time and the work later completes","featureId":312,"featureName":"Restart does not run work early","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.l3.server-time-specifications","points":3,"provenBy":null,"requiresFeatures":["ecommerce.l3.scheduled-restocks-features"],"role":"guarantee","semantics":[{"do":"wait"},{"do":"reload"},{"atMost":100000,"do":"expectElapsed","since":"restock-start"},{"do":"dbExpectStock","item":"Espresso Machine","plus":0,"relativeTo":"before"},{"count":1,"do":"expect"},{"atMost":100000,"do":"expectElapsed","since":"restock-start"},{"do":"wait","since":"restock-start-accepted"},{"do":"dbExpectStock","item":"Espresso Machine","plus":4,"relativeTo":"before"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","ifAvailable":true},{"do":"click","ifAvailable":true},{"do":"expect"},{"absent":true,"do":"expect"}],"source":"scenarios/03-server-time.json","stableKey":"ecommerce.l3.server-time.server-time.312a","statedBy":"A pending restock does not run early after a restart.","withheld":null},{"category":"production","checkGroupId":"server-time","criterionId":"313a","description":"a reservation expires while its browser is closed","featureId":313,"featureName":"A browser is not the clock","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.l3.server-time-specifications","points":3,"provenBy":null,"requiresFeatures":["ecommerce.l3.reservations-features"],"role":"guarantee","semantics":[{"do":"wait"},{"do":"reload"},{"do":"expectNumber","plus":0,"relativeTo":"before"}],"source":"scenarios/03-server-time.json","stableKey":"ecommerce.l3.server-time.server-time.313a","statedBy":"A reservation expires without an open browser.","withheld":null},{"category":"production","checkGroupId":"account-state-recovery","criterionId":"105b","description":"the same account and cart survive the connection dropping and coming back","featureId":105,"featureName":"An account keeps what belongs to it","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.state-durability","points":1,"provenBy":null,"requiresFeatures":["ecommerce.feature.accounts","ecommerce.feature.checkout"],"role":"guarantee","semantics":[{"do":"setOffline","offline":true},{"do":"click"},{"do":"setOffline","offline":false},{"contains":"pat","do":"expect"},{"do":"click","unlessVisible":"cart-total"},{"contains":"Keyboard","do":"expect"},{"contains":"Headphones","do":"expect"}],"source":"scenarios/progression-account-state-reconnect.json","stableKey":"ecommerce.spec.state-durability.account-state-recovery.105b","statedBy":"the signed-in account and its current data remain available after reconnecting","withheld":null},{"category":"production","checkGroupId":"account-state-recovery","criterionId":"105a","description":"cart and order history survive reload and backend restart, including a fresh account login","featureId":105,"featureName":"An account keeps what belongs to it","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.state-durability","points":1,"provenBy":null,"requiresFeatures":["ecommerce.feature.accounts","ecommerce.feature.checkout"],"role":"guarantee","semantics":[{"do":"click"},{"do":"click","unlessVisible":"cart-total"},{"do":"click"},{"do":"click","ifAvailable":true},{"do":"click","ifAvailable":true},{"do":"click"},{"do":"click","unlessVisible":"cart-total"},{"contains":"Keyboard","do":"expect"},{"do":"reload"},{"contains":"pat","do":"expect"},{"do":"click","unlessVisible":"cart-total"},{"contains":"Keyboard","do":"expect"},{"do":"reload"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"contains":"Headphones","count":1,"do":"expect"},{"do":"restartBackend"},{"do":"freshClient"},{"do":"signIn","name":"pat"},{"do":"click","unlessVisible":"cart-total"},{"contains":"Keyboard","count":1,"do":"expect"},{"do":"click","ifAvailable":true},{"do":"click","unlessVisible":"order-item"},{"contains":"Headphones","count":1,"do":"expect"}],"source":"scenarios/progression-account-state-reload.json","stableKey":"ecommerce.spec.state-durability.account-state-recovery.105a","statedBy":"the signed-in account, cart, and orders persist across a page reload","withheld":null},{"category":"production","checkGroupId":"automatic-reorder-access","criterionId":"502c","description":"a customer cannot see or replay automatic reorder management","featureId":502,"featureName":"Warehouse staff manage automatic reorder rules","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"provenBy":null,"requiresFeatures":["ecommerce.progression.automatic-reorder"],"role":"guarantee","semantics":[{"absent":true,"do":"expect"},{"do":"fill","text":"Desk Lamp"},{"do":"fill","text":"1"},{"do":"fill","text":"9"},{"action":"saveReorderRule","do":"callAction","from":"staff","input":{"attribute":"data-action-input","testid":"reorder-submit"},"namedAction":{"args":[0,1,9],"id":"saveReorderRule","method":"PUT","params":[{"in":"path","name":"itemId","placeholder":"{itemId}","wireType":"u64"},{"in":"body","name":"threshold"},{"in":"body","name":"quantity"}],"path":"/api/reorders/{itemId}","reducer":"save_reorder_rule"}},{"do":"expectActionOutcome","outcome":"refused","routeProvenBy":"staff"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"do":"click","ifAvailable":true},{"do":"click","unlessVisible":"reorder-submit"},{"attribute":"data-threshold","contains":"Desk Lamp","count":1,"do":"expect","value":"2"},{"attribute":"data-quantity","contains":"Desk Lamp","do":"expect","value":"5"}],"source":"scenarios/progression-automatic-reorder-access.json","stableKey":"ecommerce.spec.access-control.automatic-reorder-access.502c","statedBy":"Only warehouse staff can manage automatic reorder rules.","withheld":null},{"category":"production","checkGroupId":"automatic-reorder-deduplication","criterionId":"502b","description":"more sales do not duplicate a pending restock","featureId":502,"featureName":"Warehouse staff manage automatic reorder rules","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.transactional-integrity","points":2,"provenBy":null,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.progression.automatic-reorder"],"role":"guarantee","semantics":[{"action":"buy","do":"callAction","input":{"attribute":"data-buy-input","contains":"Desk Lamp","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"}},{"do":"expectActionOutcome","outcome":"accepted"},{"action":"buy","do":"callAction","input":{"attribute":"data-buy-input","contains":"Desk Lamp","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"}},{"do":"expectActionOutcome","outcome":"accepted"},{"do":"dbExpectStock","equals":0,"item":"Desk Lamp"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","ifAvailable":true},{"do":"click","unlessVisible":"admin-revenue"},{"do":"click","ifAvailable":true},{"do":"expect"},{"do":"expectElementCount","equals":1},{"attribute":"data-quantity","contains":"Desk Lamp","count":1,"do":"expect","value":"5"}],"source":"scenarios/progression-automatic-reorder-duplicate.json","stableKey":"ecommerce.spec.transactional-integrity.automatic-reorder-deduplication.502b","statedBy":"A pending automatic restock is not scheduled twice.","withheld":null},{"category":"feature","checkGroupId":"automatic-reorder","criterionId":"502a","description":"crossing the threshold creates one pending restock","featureId":502,"featureName":"Warehouse staff manage automatic reorder rules","note":null,"packId":"ecommerce.progression.automatic-reorder","points":3,"provenBy":null,"requiresFeatures":["ecommerce.feature.purchasing"],"role":"feature","semantics":[{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","ifAvailable":true},{"do":"click","unlessVisible":"admin-revenue"},{"do":"click","ifAvailable":true},{"do":"expect"},{"do":"expectElementCount","equals":0},{"action":"buy","do":"callAction","input":{"attribute":"data-buy-input","contains":"Desk Lamp","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"}},{"do":"expectActionOutcome","outcome":"accepted"},{"do":"dbExpectStock","equals":2,"item":"Desk Lamp"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","ifAvailable":true},{"do":"click","unlessVisible":"admin-revenue"},{"do":"click","ifAvailable":true},{"do":"expect"},{"do":"expectElementCount","equals":1},{"attribute":"data-quantity","contains":"Desk Lamp","count":1,"do":"expect","value":"5"}],"source":"scenarios/progression-automatic-reorder.json","stableKey":"ecommerce.progression.automatic-reorder.automatic-reorder.502a","statedBy":"Crossing a reorder threshold schedules a restock.","withheld":null},{"category":"production","checkGroupId":"books-balance","criterionId":"107a","description":"revenue rises by exactly what was bought","featureId":107,"featureName":"The books balance","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.transactional-integrity","points":1,"provenBy":null,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.warehouse-admin"],"role":"guarantee","semantics":[{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","ifAvailable":true},{"do":"click","unlessVisible":"admin-revenue"},{"do":"expectNumber","plus":58,"relativeTo":"revenue-before"}],"source":"scenarios/progression-books-balance.json","stableKey":"ecommerce.spec.transactional-integrity.books-balance.107a","statedBy":"total revenue equals the sum of order totals","withheld":null},{"category":"production","checkGroupId":"books-balance","criterionId":"107b","description":"what the store sold is what left the warehouses, and a fresh client agrees","featureId":107,"featureName":"The books balance","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.transactional-integrity","points":1,"provenBy":null,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.warehouse-admin"],"role":"guarantee","semantics":[{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","ifAvailable":true},{"do":"expectNumber","plus":-2,"relativeTo":"stand-before"},{"do":"freshClient"},{"do":"expectNumber","plus":-2,"relativeTo":"stand-before"}],"source":"scenarios/progression-books-balance.json","stableKey":"ecommerce.spec.transactional-integrity.books-balance.107b","statedBy":"warehouse totals and a fresh storefront agree with completed sales","withheld":null},{"category":"feature","checkGroupId":"bundle-checkout","criterionId":"741a","description":"adding a bundle reserves its components and checkout records the bundle price once","featureId":741,"featureName":"Bundle checkout","note":null,"packId":"ecommerce.feature.bundle-checkout","points":2,"provenBy":null,"role":"feature","semantics":[{"do":"click"},{"do":"dbExpectStock","equals":4,"item":"Keyboard","warehouse":"East"},{"do":"dbExpectStock","equals":3,"item":"Desk Lamp","warehouse":"East"},{"do":"click"},{"do":"click"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click"},{"contains":"Checkout bundle","count":1,"do":"expect"},{"do":"expectNumber","equals":75},{"do":"dbExpectStock","equals":4,"item":"Keyboard","warehouse":"East"},{"do":"dbExpectStock","equals":3,"item":"Desk Lamp","warehouse":"East"},{"do":"dbExpectStock","equals":0,"item":"Keyboard","warehouse":"West"},{"do":"dbExpectStock","equals":0,"item":"Desk Lamp","warehouse":"West"}],"source":"scenarios/progression-bundle-checkout.json","stableKey":"ecommerce.feature.bundle-checkout.bundle-checkout.741a","statedBy":null,"withheld":null},{"category":"production","checkGroupId":"bundle-744","criterionId":"744a","description":"two competing reservations accept exactly one whole bundle without consuming extra components","featureId":744,"featureName":"Competing bundle reservations","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.bundle-integrity","points":3,"provenBy":null,"requiresFeatures":["ecommerce.feature.bundle-checkout"],"role":"guarantee","semantics":[{"action":"addBundleToCart","do":"callConcurrently","input":{"attribute":"data-bundle-input","contains":"Scarce bundle","testid":"bundle-card"},"namedAction":{"args":[0],"id":"addBundleToCart","params":[{"in":"body","name":"bundleId","wireType":"u64"}],"path":"/api/cart/bundles","reducer":"add_bundle_to_cart"}},{"accepted":1,"do":"expectCallOutcomes"},{"do":"dbExpectStock","equals":0,"item":"Keyboard","warehouse":"East"},{"do":"dbExpectStock","equals":0,"item":"Desk Lamp","warehouse":"East"},{"do":"reload"},{"do":"reload"},{"do":"click"},{"do":"click"},{"contains":"Scarce bundle","do":"expectActorsWith","equals":1,"maxEach":1},{"do":"click","ifAvailable":true},{"do":"click","ifAvailable":true},{"do":"dbExpectStock","equals":2,"item":"Keyboard","warehouse":"East"},{"do":"dbExpectStock","equals":1,"item":"Desk Lamp","warehouse":"East"}],"source":"scenarios/progression-bundle-checkout.json","stableKey":"ecommerce.spec.bundle-integrity.bundle-744.744a","statedBy":null,"withheld":null},{"category":"production","checkGroupId":"bundle-745","criterionId":"745a","description":"a missing component refuses the reservation without taking available stock or adding a cart line","featureId":745,"featureName":"Incomplete bundle stock","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.bundle-integrity","points":3,"provenBy":null,"requiresFeatures":["ecommerce.feature.bundle-checkout"],"role":"guarantee","semantics":[{"action":"addBundleToCart","do":"callAction","input":{"attribute":"data-bundle-input","contains":"Unavailable bundle","testid":"bundle-card"},"namedAction":{"args":[0],"id":"addBundleToCart","params":[{"in":"body","name":"bundleId","wireType":"u64"}],"path":"/api/cart/bundles","reducer":"add_bundle_to_cart"}},{"do":"expectActionOutcome","outcome":"application-refused"},{"do":"dbExpectStock","equals":2,"item":"Keyboard","warehouse":"East"},{"do":"dbExpectStock","equals":0,"item":"Desk Lamp","warehouse":"East"},{"do":"click"},{"absent":true,"contains":"Unavailable bundle","do":"expect"}],"source":"scenarios/progression-bundle-checkout.json","stableKey":"ecommerce.spec.bundle-integrity.bundle-745.745a","statedBy":null,"withheld":null},{"category":"production","checkGroupId":"bundle-746","criterionId":"746a","description":"an expired reservation releases each component once across a backend restart","featureId":746,"featureName":"Bundle reservation restart","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.bundle-integrity","points":3,"provenBy":null,"requiresFeatures":["ecommerce.feature.bundle-checkout"],"role":"guarantee","semantics":[{"do":"click"},{"do":"dbExpectStock","equals":4,"item":"Keyboard","warehouse":"East"},{"do":"dbExpectStock","equals":3,"item":"Desk Lamp","warehouse":"East"},{"do":"restartBackend"},{"do":"wait"},{"do":"reload"},{"do":"ensureSignedIn","name":"bundle-expiry"},{"do":"click"},{"do":"expect"},{"do":"dbExpectStock","equals":6,"item":"Keyboard","warehouse":"East"},{"do":"dbExpectStock","equals":4,"item":"Desk Lamp","warehouse":"East"},{"do":"restartBackend"},{"do":"dbExpectStock","equals":6,"item":"Keyboard","warehouse":"East"},{"do":"dbExpectStock","equals":4,"item":"Desk Lamp","warehouse":"East"}],"source":"scenarios/progression-bundle-checkout.json","stableKey":"ecommerce.spec.bundle-integrity.bundle-746.746a","statedBy":null,"withheld":null},{"category":"production","checkGroupId":"bundle-747","criterionId":"747a","description":"two checkout requests consume one reservation and create one paid bundle","featureId":747,"featureName":"Repeated bundle checkout","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.bundle-integrity","points":3,"provenBy":null,"requiresFeatures":["ecommerce.feature.bundle-checkout"],"role":"guarantee","semantics":[{"action":"checkout","do":"callConcurrently"},{"accepted":1,"do":"expectCallOutcomes"},{"do":"reload"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click"},{"contains":"Repeated bundle","count":1,"do":"expect"},{"do":"expectNumber","equals":75},{"do":"dbExpectStock","equals":4,"item":"Keyboard","warehouse":"East"},{"do":"dbExpectStock","equals":3,"item":"Desk Lamp","warehouse":"East"}],"source":"scenarios/progression-bundle-checkout.json","stableKey":"ecommerce.spec.bundle-integrity.bundle-747.747a","statedBy":null,"withheld":null},{"category":"feature","checkGroupId":"bundle-returns","criterionId":"742a","description":"returning a shipped bundle refunds the paid price and restores original components after its definition changes","featureId":742,"featureName":"Historical bundle return","note":null,"packId":"ecommerce.feature.bundle-returns","points":2,"provenBy":null,"role":"feature","semantics":[{"do":"fill","text":"Historical bundle"},{"do":"fill","text":"9.00"},{"do":"fill","text":"[{\"item\":\"Keyboard\",\"quantity\":1},{\"item\":\"Desk Lamp\",\"quantity\":3}]"},{"do":"click"},{"contains":"Historical bundle","do":"expect"},{"do":"click"},{"do":"expect","ignoreCase":true,"value":"returned"},{"do":"expectNumber","equals":75},{"do":"dbExpectStock","equals":6,"item":"Keyboard","warehouse":"East"},{"do":"dbExpectStock","equals":4,"item":"Desk Lamp","warehouse":"East"},{"do":"dbExpectStock","equals":0,"item":"Keyboard","warehouse":"West"},{"do":"dbExpectStock","equals":0,"item":"Desk Lamp","warehouse":"West"}],"source":"scenarios/progression-bundle-returns.json","stableKey":"ecommerce.feature.bundle-returns.bundle-returns.742a","statedBy":null,"withheld":null},{"category":"production","checkGroupId":"bundle-742","criterionId":"742b","description":"replaying a completed bundle return after restart does not refund or restock it twice","featureId":742,"featureName":"Historical bundle return","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.bundle-integrity","points":3,"provenBy":null,"requiresFeatures":["ecommerce.feature.bundle-returns"],"role":"guarantee","semantics":[{"do":"restartBackend"},{"do":"reload"},{"do":"ensureSignedIn","name":"Historical bundle"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click"},{"action":"returnBundle","do":"callAction","input":{"attribute":"data-bundle-return-input","contains":"Historical bundle","testid":"order-item"},"namedAction":{"args":[0],"id":"returnBundle","params":[{"in":"path","name":"orderId","placeholder":":orderId","wireType":"u64"}],"path":"/api/bundle-orders/:orderId/return","reducer":"return_bundle"}},{"do":"reload"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click"},{"do":"expectNumber","equals":75},{"do":"dbExpectStock","equals":6,"item":"Keyboard","warehouse":"East"},{"do":"dbExpectStock","equals":4,"item":"Desk Lamp","warehouse":"East"}],"source":"scenarios/progression-bundle-returns.json","stableKey":"ecommerce.spec.bundle-integrity.bundle-742.742b","statedBy":null,"withheld":null},{"category":"production","checkGroupId":"bundle-748","criterionId":"748a","description":"another customer cannot return a paid bundle by submitting its order ID","featureId":748,"featureName":"Bundle return ownership","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.bundle-integrity","points":3,"provenBy":null,"requiresFeatures":["ecommerce.feature.bundle-returns"],"role":"guarantee","semantics":[{"action":"returnBundle","do":"callAction","from":"buyer","input":{"attribute":"data-bundle-return-input","contains":"Private bundle","testid":"order-item"},"namedAction":{"args":[0],"id":"returnBundle","params":[{"in":"path","name":"orderId","placeholder":":orderId","wireType":"u64"}],"path":"/api/bundle-orders/:orderId/return","reducer":"return_bundle"}},{"do":"expectActionOutcome","outcome":"application-refused"},{"do":"reload"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click"},{"do":"expect","ignoreCase":true,"value":"shipped"},{"do":"dbExpectStock","equals":4,"item":"Keyboard","warehouse":"East"},{"do":"dbExpectStock","equals":3,"item":"Desk Lamp","warehouse":"East"},{"do":"click"},{"do":"expectNumber","equals":75},{"do":"dbExpectStock","equals":6,"item":"Keyboard","warehouse":"East"},{"do":"dbExpectStock","equals":4,"item":"Desk Lamp","warehouse":"East"}],"source":"scenarios/progression-bundle-returns.json","stableKey":"ecommerce.spec.bundle-integrity.bundle-748.748a","statedBy":null,"withheld":null},{"category":"feature","checkGroupId":"cart","criterionId":"4a","description":"adding the same item twice raises its quantity instead of adding a second line","featureId":4,"featureName":"Account cart and checkout","note":null,"packId":"ecommerce.feature.cart","points":1,"provenBy":null,"role":"feature","semantics":[{"do":"click"},{"do":"wait"},{"do":"click","ifAvailable":true},{"do":"click","ifAvailable":true},{"do":"click"},{"do":"click","unlessVisible":"cart-total"},{"contains":"Headphones","count":1,"do":"expect"},{"do":"expectNumber","equals":2}],"source":"scenarios/progression-cart-checkout.json","stableKey":"ecommerce.feature.cart-checkout.cart.4a","statedBy":"Adding an existing cart item increases its quantity.","withheld":null},{"category":"feature","checkGroupId":"cart","criterionId":"4d","description":"checkout creates one order, reduces stock, and empties the cart","featureId":4,"featureName":"Account cart and checkout","note":null,"packId":"ecommerce.feature.checkout","points":2,"provenBy":null,"role":"feature","semantics":[{"do":"expectNumber","equals":100},{"do":"click"},{"do":"click","unlessVisible":"cart-total"},{"do":"expectNumber","equals":1},{"do":"click"},{"do":"wait"},{"do":"reload"},{"do":"ensureSignedIn","name":"cart-checkout"},{"do":"click","unlessVisible":"cart-total"},{"do":"expectNumber","equals":0},{"do":"click","ifAvailable":true},{"do":"click","ifAvailable":true},{"do":"expectNumber","equals":99},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"contains":"Desk Lamp","count":1,"do":"expect"}],"source":"scenarios/progression-cart-checkout.json","stableKey":"ecommerce.feature.cart-checkout.cart.4d","statedBy":"Checkout creates one order, reduces stock, and empties the cart.","withheld":null},{"category":"feature","checkGroupId":"cart-recovery","criterionId":"503a","description":"restoring an expired cart reserves available items again","featureId":503,"featureName":"Expired carts restore only available items","note":null,"packId":"ecommerce.progression.cart-recovery","points":3,"provenBy":null,"role":"feature","semantics":[{"do":"reload"},{"do":"ensureSignedIn","name":"cart-recovery-available"},{"do":"expect"},{"do":"expectNumber","equals":0},{"as":"restore-available-shopper","do":"recordNumber"},{"do":"click"},{"do":"click"},{"contains":"Keyboard","do":"expect"},{"absent":true,"do":"expect"},{"do":"expectNumber","equals":1},{"do":"reload"},{"do":"ensureSignedIn","name":"cart-recovery-available"},{"do":"click","ifAvailable":true},{"do":"click","unlessVisible":"item-card"},{"do":"expectNumber","plus":-1,"relativeTo":"restore-available-shopper"}],"source":"scenarios/progression-cart-recovery.json","stableKey":"ecommerce.progression.cart-recovery.cart-recovery.503a","statedBy":"A customer can restore the available items from an expired cart.","withheld":null},{"category":"feature","checkGroupId":"cart-recovery","criterionId":"503b","description":"a partial restore keeps available items and names each unavailable item","featureId":503,"featureName":"Expired carts restore only available items","note":null,"packId":"ecommerce.progression.cart-recovery","points":3,"provenBy":null,"role":"feature","semantics":[{"do":"reload"},{"do":"ensureSignedIn","name":"cart-recovery-partial"},{"do":"expect"},{"do":"expectNumber","equals":0},{"as":"restore-partial-shopper","do":"recordNumber"},{"do":"dbSetStock","item":"Desk Lamp","quantity":0,"warehouse":"East"},{"do":"dbSetStock","item":"Desk Lamp","quantity":0,"warehouse":"West"},{"do":"click"},{"do":"click"},{"contains":"Gaming Mouse","do":"expect"},{"absent":true,"contains":"Desk Lamp","do":"expect"},{"contains":"Desk Lamp","do":"expect"},{"do":"expectNumber","equals":1},{"do":"reload"},{"do":"ensureSignedIn","name":"cart-recovery-partial"},{"do":"click","ifAvailable":true},{"do":"click","unlessVisible":"item-card"},{"do":"expectNumber","plus":-1,"relativeTo":"restore-partial-shopper"}],"source":"scenarios/progression-cart-recovery.json","stableKey":"ecommerce.progression.cart-recovery.cart-recovery.503b","statedBy":"Restore the available items and list each item that could not be restored.","withheld":null},{"category":"feature","checkGroupId":"catalog-management","criterionId":"622a","description":"a new product reaches the public catalog","featureId":622,"featureName":"Catalog management","note":null,"packId":"ecommerce.progression.catalog-management","points":2,"provenBy":null,"role":"feature","semantics":[{"contains":"Travel Mug","do":"expect"}],"source":"scenarios/progression-catalog-management.json","stableKey":"ecommerce.progression.catalog-management.catalog-management.622a","statedBy":"Authorized staff can add products.","withheld":null},{"category":"feature","checkGroupId":"catalog-management","criterionId":"622b","description":"the product exposes its named variants","featureId":622,"featureName":"Catalog management","note":null,"packId":"ecommerce.progression.catalog-management","points":2,"provenBy":null,"role":"feature","semantics":[{"do":"openItem","item":"Travel Mug","unlessVisible":"item-variant"},{"contains":"Black","do":"expectElementCount","equals":1},{"contains":"Silver","do":"expectElementCount","equals":1}],"source":"scenarios/progression-catalog-management.json","stableKey":"ecommerce.progression.catalog-management.catalog-management.622b","statedBy":"Products can have named variants.","withheld":null},{"category":"production","checkGroupId":"checkout-crash-integrity","criterionId":"910a","description":"interrupted checkout recovers to the prepared cart or one complete order with the cart cleared after each independent process crash","featureId":910,"featureName":"Checkout crash recovery","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.state-durability","points":1,"provenBy":null,"requiresFeatures":["ecommerce.feature.checkout"],"role":"guarantee","semantics":[{"do":"expectCrashCheckout","from":"database-crash-observation","verdict":"atomicity"},{"do":"expectCrashCheckout","from":"application-crash-observation","verdict":"atomicity"}],"source":"scenarios/progression-checkout-crash.json","stableKey":"ecommerce.spec.state-durability.checkout-crash-integrity.910a","statedBy":null,"withheld":null},{"category":"production","checkGroupId":"checkout-crash-durability","criterionId":"910b","description":"acknowledged checkout is not rolled back and earlier orders remain unchanged after each independent process crash","featureId":910,"featureName":"Checkout crash recovery","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.state-durability","points":1,"provenBy":null,"requiresFeatures":["ecommerce.feature.checkout"],"role":"guarantee","semantics":[{"do":"expectCrashCheckout","from":"database-crash-observation","verdict":"durability"},{"do":"expectCrashCheckout","from":"application-crash-observation","verdict":"durability"}],"source":"scenarios/progression-checkout-crash.json","stableKey":"ecommerce.spec.state-durability.checkout-crash-durability.910b","statedBy":null,"withheld":null},{"category":"production","checkGroupId":"payment-records","criterionId":"623a","description":"checkout records the exact paid amount","featureId":623,"featureName":"Payment records","note":null,"packId":"ecommerce.progression.payment-records","points":3,"provenBy":null,"role":"feature","semantics":[{"do":"expect","ignoreCase":true,"value":"paid"},{"do":"expectNumber","plus":0,"relativeTo":"payment-total"}],"source":"scenarios/progression-core-business.json","stableKey":"ecommerce.progression.payment-records.payment-records.623a","statedBy":"Checkout records the amount paid on the order.","withheld":null},{"category":"production","checkGroupId":"payment-deduplication","criterionId":"623b","description":"one checkout has one payment record","featureId":623,"featureName":"Payment records","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.transactional-integrity","points":2,"provenBy":null,"requiresFeatures":["ecommerce.progression.payment-records"],"role":"guarantee","semantics":[{"do":"expectElementCount","equals":1}],"source":"scenarios/progression-core-business.json","stableKey":"ecommerce.spec.transactional-integrity.payment-deduplication.623b","statedBy":"A checkout does not create duplicate payments.","withheld":null},{"category":"feature","checkGroupId":"customer-profile","criterionId":"620c","description":"the owner can save and view a customer profile","featureId":620,"featureName":"Customer profile","note":null,"packId":"ecommerce.progression.customer-profile","points":1,"provenBy":null,"role":"feature","semantics":[{"do":"click","ifAvailable":true},{"do":"click","ifAvailable":true},{"do":"click","unlessVisible":"profile-address-summary"},{"contains":"14 Market Street {user:profilemarker}","do":"expect"}],"source":"scenarios/progression-customer-profile.json","stableKey":"ecommerce.progression.customer-profile.customer-profile.620c","statedBy":"A signed-in customer can save and view their name and shipping address.","withheld":null},{"category":"production","checkGroupId":"customer-profile-reload","criterionId":"620a","description":"the saved profile survives reload and backend restart in a fresh browser","featureId":620,"featureName":"Customer profile","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.state-durability","points":2,"provenBy":null,"requiresFeatures":["ecommerce.progression.customer-profile"],"role":"guarantee","semantics":[{"do":"reload"},{"do":"ensureSignedIn","name":"profile-owner"},{"do":"click"},{"contains":"14 Market Street {user:profilemarker}","do":"expect"},{"do":"restartBackend"},{"do":"freshClient"},{"do":"signIn","name":"profile-owner"},{"do":"click"},{"contains":"14 Market Street {user:profilemarker}","do":"expect"}],"source":"scenarios/progression-customer-profile.json","stableKey":"ecommerce.spec.state-durability.customer-profile-reload.620a","statedBy":"The saved profile remains after a reload.","withheld":null},{"category":"production","checkGroupId":"customer-profile-privacy","criterionId":"620b","description":"another customer neither sees nor receives the owner's private address","featureId":620,"featureName":"Customer profile","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"provenBy":null,"requiresFeatures":["ecommerce.progression.customer-profile"],"role":"guarantee","semantics":[{"do":"reload"},{"do":"signUp","name":"profile-private-owner"},{"do":"click"},{"do":"fill","text":"Avery Stone"},{"do":"fill","text":"14 Market Street {user:profilemarker}"},{"do":"click"},{"do":"reload"},{"do":"ensureSignedIn","name":"profile-private-owner"},{"do":"click"},{"contains":"14 Market Street {user:profilemarker}","do":"expect"},{"contains":"14 Market Street {user:profilemarker}","do":"expectReceived"},{"do":"reload"},{"do":"signUp","name":"profile-other"},{"do":"click"},{"absent":true,"contains":"14 Market Street {user:profilemarker}","do":"expect"},{"contains":"14 Market Street {user:profilemarker}","do":"expectNotReceived"}],"source":"scenarios/progression-customer-profile.json","stableKey":"ecommerce.spec.access-control.customer-profile-privacy.620b","statedBy":"Each customer can see only their own profile.","withheld":null},{"category":"feature","checkGroupId":"delivery-notification-delivery","criterionId":"501a","description":"the order owner receives one delivery notification","featureId":501,"featureName":"Delivery creates one private notification","note":null,"packId":"ecommerce.progression.delivery-notifications","points":3,"provenBy":null,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.progression.fulfilment-queue"],"role":"feature","semantics":[{"do":"reload"},{"do":"ensureSignedIn","name":"delivery-owner"},{"do":"click","unlessVisible":"notifications-panel"},{"attribute":"aria-busy","do":"expect","value":"false"},{"contains":"Desk Lamp","do":"expectElementCount","equals":1}],"source":"scenarios/progression-delivery-notifications.json","stableKey":"ecommerce.progression.delivery-notifications.delivery-notification-delivery.501a","statedBy":"A delivered order creates one notification for its owner.","withheld":null},{"category":"production","checkGroupId":"delivery-notification-privacy","criterionId":"501b","description":"another customer cannot see the delivery notification","featureId":501,"featureName":"Delivery creates one private notification","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"provenBy":null,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.progression.delivery-notifications","ecommerce.progression.fulfilment-queue"],"role":"guarantee","semantics":[{"do":"reload"},{"do":"ensureSignedIn","name":"delivery-owner"},{"do":"click","unlessVisible":"notifications-panel"},{"contains":"Desk Lamp","do":"expectElementCount","equals":1},{"do":"click","unlessVisible":"notifications-panel"},{"attribute":"aria-busy","do":"expect","value":"false"},{"absent":true,"contains":"Desk Lamp","do":"expect"}],"source":"scenarios/progression-delivery-notifications.json","stableKey":"ecommerce.spec.access-control.delivery-notification-privacy.501b","statedBy":"Delivery notifications are private to the order owner.","withheld":null},{"category":"feature","checkGroupId":"faceted-search","criterionId":"401a","description":"category, price, and availability filters apply together","featureId":401,"featureName":"Filters compose","note":null,"packId":"ecommerce.progression.faceted-search","points":3,"provenBy":null,"role":"feature","semantics":[{"contains":"Coffee Grinder","do":"expectElementCount","equals":1},{"do":"click"},{"do":"click","ifAvailable":true},{"do":"waitUntilAbsent"},{"contains":"Air Purifier","do":"expectElementCount","equals":1},{"absent":true,"contains":"USB Cable","do":"expect"},{"absent":true,"contains":"Desk Lamp","do":"expect"},{"absent":true,"contains":"Espresso Machine","do":"expect"},{"absent":true,"contains":"Gaming Mouse","do":"expect"}],"source":"scenarios/progression-faceted-filters.json","stableKey":"ecommerce.progression.faceted-search.faceted-search.401a","statedBy":"Apply all selected filters together","withheld":null},{"category":"feature","checkGroupId":"faceted-search","criterionId":"402a","description":"moving between pages returns the same ordered items without duplicates","featureId":402,"featureName":"Pages are stable","note":null,"packId":"ecommerce.progression.faceted-search","points":3,"provenBy":null,"role":"feature","semantics":[{"do":"expectSequence","equals":["Air Purifier","Bluetooth Speaker","Coffee Grinder","Desk Lamp","Espresso Machine","Gaming Mouse","Headphones","Induction Cooktop","Keyboard","Laptop Stand"]},{"do":"click"},{"do":"expectSequence","equals":["Mirrorless Camera","USB Cable","Webcam"]},{"do":"click"},{"do":"expectSequence","equals":["Air Purifier","Bluetooth Speaker","Coffee Grinder","Desk Lamp","Espresso Machine","Gaming Mouse","Headphones","Induction Cooktop","Keyboard","Laptop Stand"]}],"source":"scenarios/progression-faceted-pagination.json","stableKey":"ecommerce.progression.faceted-search.faceted-search.402a","statedBy":"Moving between pages must not omit or repeat an item","withheld":null},{"category":"production","checkGroupId":"managed-support-privacy","criterionId":"613b","description":"another customer cannot read or reply to the managed case","featureId":613,"featureName":"Managed support privacy","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":1,"provenBy":null,"requiresFeatures":["ecommerce.progression.managed-support"],"role":"guarantee","semantics":[{"do":"reload"},{"do":"ensureSignedIn","name":"managed-private-owner"},{"do":"click"},{"contains":"Private managed case {user:casemarker}","do":"expect"},{"contains":"Private managed case {user:casemarker}","do":"expectReceived"},{"absent":true,"contains":"Private managed case {user:casemarker}","do":"expect"},{"contains":"Private managed case {user:casemarker}","do":"expectNotReceived"},{"do":"fill","text":"Owner-only update"},{"do":"click"},{"do":"replayAs","from":"owner","match":"Owner-only update","namedAction":{"args":[0,"Owner-only update"],"id":"replySupport","method":"POST","params":[{"in":"path","name":"ticketId","placeholder":":id","wireType":"u64"},{"in":"body","name":"body"}],"path":"/api/support/:id/replies","reducer":"reply_support"},"namedTarget":{"attribute":"data-entity-id","contains":"Private managed case {user:casemarker}","testid":"support-ticket","valueType":"string"}},{"allowNotFound":true,"do":"expectReplayRejected"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"do":"click","ifAvailable":true,"unlessVisible":"support-assignee"},{"do":"click","ifAvailable":true,"unlessVisible":"support-assignee"},{"contains":"Private managed case {user:casemarker}","do":"expect"},{"contains":"Owner-only update","do":"expectElementCount","equals":1},{"contains":"Owner-only update","do":"expectReceived"},{"contains":"Owner-only update","do":"expectNotReceived"}],"source":"scenarios/progression-managed-support-privacy.json","stableKey":"ecommerce.spec.access-control.managed-support-privacy.613b","statedBy":"A customer can access only cases that belong to their account.","withheld":null},{"category":"feature","checkGroupId":"managed-support","criterionId":"613c","description":"staff can update a support case and the customer can reply","featureId":613,"featureName":"Shared managed support case","note":null,"packId":"ecommerce.progression.managed-support","points":1,"provenBy":null,"role":"feature","semantics":[{"do":"fill","text":"in progress"},{"do":"click"},{"do":"fill","text":"Case received."},{"do":"click"},{"do":"reload"},{"do":"ensureSignedIn","name":"managed-shared-owner"},{"do":"click"},{"contains":"in progress","do":"expect"},{"contains":"Case received.","do":"expect"},{"do":"fill","text":"Thank you."},{"do":"click"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"do":"click","unlessVisible":"support-assignee"},{"do":"click","ifAvailable":true,"unlessVisible":"support-assignee"},{"contains":"Thank you.","do":"expect"}],"source":"scenarios/progression-managed-support-shared.json","stableKey":"ecommerce.progression.managed-support.managed-support.613c","statedBy":"Customers and staff can exchange replies and update the status of a support case.","withheld":null},{"category":"production","checkGroupId":"managed-support","criterionId":"613a","description":"the customer and staff see the same replies and status live","featureId":613,"featureName":"Shared managed support case","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.live-state","points":2,"provenBy":null,"requiresFeatures":["ecommerce.progression.managed-support"],"role":"guarantee","semantics":[{"do":"fill","text":"open"},{"do":"click"},{"contains":"open","do":"expect"},{"do":"reload"},{"do":"ensureSignedIn","name":"managed-shared-owner"},{"do":"click","unlessVisible":"support-ticket"},{"contains":"open","do":"expect"},{"do":"fill","text":"in progress"},{"do":"click"},{"do":"fill","text":"We are investigating."},{"do":"click"},{"contains":"in progress","do":"expect"},{"contains":"We are investigating.","do":"expect"},{"do":"fill","text":"Thank you for the update."},{"do":"click"},{"contains":"Thank you for the update.","do":"expect"}],"source":"scenarios/progression-managed-support-shared.json","stableKey":"ecommerce.spec.live-state.managed-support.613a","statedBy":"Customers and authorized staff use one shared support case.","withheld":null},{"category":"feature","checkGroupId":"notification-preferences","criterionId":"630c","description":"the customer can save a notification choice","featureId":630,"featureName":"Account notification preferences","note":null,"packId":"ecommerce.progression.notification-preferences","points":1,"provenBy":null,"role":"feature","semantics":[{"do":"click","ifAvailable":true},{"do":"click","ifAvailable":true},{"do":"click","unlessVisible":"notification-order"},{"attribute":"data-state","do":"expect","value":"on"}],"source":"scenarios/progression-notification-preferences.json","stableKey":"ecommerce.progression.notification-preferences.notification-preferences.630c","statedBy":"Signed-in customers can turn order and stock notifications on or off.","withheld":null},{"category":"production","checkGroupId":"notification-preferences-reload","criterionId":"630a","description":"notification choices survive reload and backend restart in a fresh browser","featureId":630,"featureName":"Account notification preferences","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.state-durability","points":2,"provenBy":null,"requiresFeatures":["ecommerce.progression.notification-preferences"],"role":"guarantee","semantics":[{"do":"reload"},{"do":"ensureSignedIn","name":"notification-owner"},{"do":"click","unlessVisible":"notification-order"},{"attribute":"data-state","do":"expect","value":"on"},{"do":"restartBackend"},{"do":"freshClient"},{"do":"signIn","name":"notification-owner"},{"do":"click","unlessVisible":"notification-order"},{"attribute":"data-state","do":"expect","value":"on"}],"source":"scenarios/progression-notification-preferences.json","stableKey":"ecommerce.spec.state-durability.notification-preferences-reload.630a","statedBy":"Notification choices persist for the account.","withheld":null},{"category":"production","checkGroupId":"notification-preferences-privacy","criterionId":"630b","description":"the owner's choice does not change another account","featureId":630,"featureName":"Account notification preferences","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"provenBy":null,"requiresFeatures":["ecommerce.progression.notification-preferences"],"role":"guarantee","semantics":[{"do":"click","unlessVisible":"notification-order"},{"attribute":"data-state","do":"expect","value":"off"}],"source":"scenarios/progression-notification-preferences.json","stableKey":"ecommerce.spec.access-control.notification-preferences-privacy.630b","statedBy":"One customer's notification choices do not affect another customer.","withheld":null},{"category":"production","checkGroupId":"open-list","criterionId":"902a","description":"one customer has the Keyboard's reviews open before another posts one; the already-open view shows that review exactly once","featureId":902,"featureName":"An open list stays current","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.live-state","points":1,"provenBy":null,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.reviews"],"role":"guarantee","semantics":[{"do":"openItem","item":"Keyboard"},{"do":"expect"},{"do":"click","ifAvailable":true,"unlessVisible":"review-rating"},{"do":"fill","text":"live-review-kbd"},{"do":"click"},{"contains":"live-review-kbd","do":"expectElementCount","equals":1},{"contains":"live-review-kbd","do":"expectElementCount","equals":1}],"source":"scenarios/progression-open-list-live.json","stableKey":"ecommerce.spec.live-state.open-list.902a","statedBy":"A view opened while a review is submitted converges to the current review list.","withheld":null},{"category":"interface","checkGroupId":"cancellation-and-return","criterionId":"3e","description":"a pending order does not offer a return button","featureId":331,"featureName":"Pending order return boundary","note":null,"packId":"ecommerce.l3.order-returns-features","points":1,"provenBy":null,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.progression.fulfilment-queue"],"role":"feature","semantics":[{"absent":true,"do":"expect"}],"source":"scenarios/progression-order-return-boundary.json","stableKey":"ecommerce.returns-pricing.cancellation-and-return.3e","statedBy":"An item from a pending order cannot be returned.","withheld":null},{"category":"production","checkGroupId":"cancellation-and-return","criterionId":"3f","description":"the server refuses a pending return without changing stock or revenue","featureId":332,"featureName":"Pending return server boundary","note":null,"packId":"ecommerce.l3.order-returns-features","points":2,"provenBy":null,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.progression.fulfilment-queue"],"role":"feature","semantics":[{"action":"returnItem","do":"callAction","input":{"attribute":"data-return-input","contains":"Desk Lamp","testid":"order-line"},"namedAction":{"args":[0,0],"id":"returnItem","method":"POST","params":[{"in":"path","name":"orderId","placeholder":"{orderId}","wireType":"u64"},{"in":"path","name":"itemId","placeholder":"{itemId}","wireType":"u64"}],"path":"/api/orders/{orderId}/items/{itemId}/return","reducer":"return_order_item"}},{"do":"expectActionOutcome","outcome":"validation-refused"},{"do":"reload"},{"do":"ensureSignedIn","name":"return-boundary"},{"do":"click","ifAvailable":true},{"do":"click","unlessVisible":"order-item"},{"do":"expect","ignoreCase":true,"value":"pending"},{"do":"dbExpectStock","item":"Desk Lamp","plus":0,"relativeTo":"pending-East","warehouse":"East"},{"do":"dbExpectStock","item":"Desk Lamp","plus":0,"relativeTo":"pending-West","warehouse":"West"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","ifAvailable":true},{"do":"click","unlessVisible":"admin-revenue"},{"do":"expectNumber","plus":0,"relativeTo":"pending-revenue"}],"source":"scenarios/progression-order-return-boundary.json","stableKey":"ecommerce.returns-pricing.cancellation-and-return.3f","statedBy":"Only shipped items can be returned.","withheld":null},{"category":"production","checkGroupId":"cancellation-and-return","criterionId":"3c","description":"returning a shipped item restores stock and revenue and marks the item returned","featureId":330,"featureName":"Completed order return","note":null,"packId":"ecommerce.l3.order-returns-features","points":3,"provenBy":null,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.progression.fulfilment-queue"],"role":"feature","semantics":[{"do":"click"},{"contains":"Keyboard","containsText":"returned","do":"expect","ignoreCase":true},{"do":"freshClient"},{"do":"signIn","name":"return-complete"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click"},{"contains":"Keyboard","containsText":"returned","do":"expect","ignoreCase":true},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","unlessVisible":"admin-revenue"},{"do":"expectNumber","plus":0,"relativeTo":"return-revenue-before"},{"do":"click","ifAvailable":true},{"do":"click","ifAvailable":true},{"do":"dbExpectStock","item":"Keyboard","plus":0,"relativeTo":"return-stock-before"}],"source":"scenarios/progression-order-return-complete.json","stableKey":"ecommerce.returns-pricing.cancellation-and-return.3c","statedBy":"An accepted return marks the item as returned, restores stock, and reduces revenue by the price paid.","withheld":null},{"category":"production","checkGroupId":"order-support-ownership","criterionId":"614b","description":"another customer cannot attach or inspect the owner's order","featureId":614,"featureName":"Order support ownership boundary","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"provenBy":null,"requiresFeatures":["ecommerce.progression.order-support"],"role":"guarantee","semantics":[{"absent":true,"contains":"Desk Lamp","do":"expect"},{"action":"linkSupportOrder","authentication":"actor","do":"callAction","input":{"attribute":"data-action-input","testid":"support-link-order"},"namedAction":{"args":[0,0],"id":"linkSupportOrder","method":"POST","params":[{"in":"path","name":"caseId","placeholder":"{caseId}","wireType":"u64"},{"in":"body","name":"orderId","wireType":"u64"}],"path":"/api/support/cases/{caseId}/order","reducer":"link_support_order"}},{"do":"expectActionOutcome","outcome":"accepted"},{"contains":"Desk Lamp","do":"expectElementCount","equals":1},{"action":"linkSupportOrder","authentication":"actor","do":"callAction","from":"owner","input":{"attribute":"data-action-input","overrides":{"caseId":{"actor":"other","attribute":"data-entity-id","contains":"Other order case","testid":"support-ticket"}},"testid":"support-link-order"},"namedAction":{"args":[0,0],"id":"linkSupportOrder","method":"POST","params":[{"in":"path","name":"caseId","placeholder":"{caseId}","wireType":"u64"},{"in":"body","name":"orderId","wireType":"u64"}],"path":"/api/support/cases/{caseId}/order","reducer":"link_support_order"}},{"do":"expectActionOutcome","outcome":"refused"},{"do":"freshClient"},{"do":"signIn","name":"order-boundary-other"},{"do":"click"},{"absent":true,"contains":"Desk Lamp","do":"expect"},{"contains":"Desk Lamp","do":"expectElementCount","equals":1}],"source":"scenarios/progression-order-support-boundary.json","stableKey":"ecommerce.spec.access-control.order-support-ownership.614b","statedBy":"A customer cannot attach or inspect another customer's order.","withheld":null},{"category":"feature","checkGroupId":"order-support-owned","criterionId":"614a","description":"the customer can link their order and staff can inspect it","featureId":614,"featureName":"Owned order support link","note":null,"packId":"ecommerce.progression.order-support","points":3,"provenBy":null,"role":"feature","semantics":[{"do":"click"},{"do":"click"},{"do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"do":"click","unlessVisible":"support-assignee"},{"do":"click","ifAvailable":true,"unlessVisible":"support-assignee"},{"contains":"Desk Lamp","do":"expect"}],"source":"scenarios/progression-order-support-owned.json","stableKey":"ecommerce.progression.order-support.order-support-owned.614a","statedBy":"A customer can attach one of their orders to a support case.","withheld":null},{"category":"feature","checkGroupId":"personalized-recommendations","criterionId":"403a","description":"recommendations follow the customer's categories, global sales, and name tie-break","featureId":403,"featureName":"Recommendations use customer activity","note":null,"packId":"ecommerce.progression.personalized-recommendations","points":4,"provenBy":null,"role":"feature","semantics":[{"contains":"Headphones","do":"expect"},{"do":"expectNumber","equals":1},{"do":"expectSequence","equals":["Gaming Mouse","Laptop Stand","Webcam"]}],"source":"scenarios/progression-personalized-recommendations.json","stableKey":"ecommerce.progression.personalized-recommendations.personalized-recommendations.403a","statedBy":"Order the remaining items by global units sold, highest first, then by item name.","withheld":null},{"category":"production","checkGroupId":"recommendation-profile-isolation","criterionId":"403b","description":"one customer's activity does not replace another customer's recommendations","featureId":403,"featureName":"Recommendations use customer activity","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"provenBy":null,"requiresFeatures":["ecommerce.progression.personalized-recommendations"],"role":"guarantee","semantics":[{"do":"click"},{"do":"waitUntilAbsent"},{"do":"expectNumber","equals":1},{"do":"expectSequence","equals":["Gaming Mouse","Laptop Stand","Webcam"]}],"source":"scenarios/progression-personalized-recommendations.json","stableKey":"ecommerce.spec.access-control.recommendation-profile-isolation.403b","statedBy":"Customer recommendation profiles are isolated.","withheld":null},{"category":"production","checkGroupId":"price-history","criterionId":"4c","description":"a price change updates an open cart and direct checkout persists the new total","featureId":420,"featureName":"Open cart price changes","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.progression.price-history-specifications","points":3,"provenBy":null,"requiresFeatures":["ecommerce.feature.checkout","ecommerce.l2.price-history-features"],"role":"guarantee","semantics":[{"do":"fill","enter":true,"text":"Desk Lamp"},{"do":"click"},{"do":"click"},{"do":"expectNumber","equals":42},{"do":"fill","text":"52.00"},{"do":"click"},{"do":"expectNumber","equals":52},{"action":"checkout","do":"callAction","namedAction":{"args":[],"id":"checkout","method":"POST","path":"/api/checkout","reducer":"checkout"}},{"do":"expectActionOutcome","outcome":"accepted"},{"do":"freshClient"},{"do":"signIn","name":"price-cart"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click"},{"contains":"Desk Lamp","count":1,"do":"expect"},{"do":"expectNumber","equals":52}],"source":"scenarios/progression-price-cart-checkout.json","stableKey":"ecommerce.returns-pricing.price-history.4c","statedBy":"The public catalog and every open cart show the new price without a reload. Checkout uses the current price.","withheld":null},{"category":"feature","checkGroupId":"product-bundles","criterionId":"740a","description":"a saved bundle shows the exact price and component quantities after reopening the application","featureId":740,"featureName":"Bundle definitions","note":null,"packId":"ecommerce.feature.product-bundles","points":2,"provenBy":null,"role":"feature","semantics":[{"do":"fill","text":"Office bundle"},{"do":"fill","text":"75.00"},{"do":"fill","text":"[{\"item\":\"Keyboard\",\"quantity\":2},{\"item\":\"Desk Lamp\",\"quantity\":1}]"},{"do":"click"},{"contains":"Office bundle","do":"expect"},{"do":"reload"},{"do":"click","unlessVisible":"bundle-card"},{"do":"expectNumber","equals":75},{"do":"expectElementCount","equals":2},{"attribute":"data-quantity","contains":"Keyboard","do":"expect","value":"2"},{"attribute":"data-quantity","contains":"Desk Lamp","do":"expect","value":"1"}],"source":"scenarios/progression-product-bundles.json","stableKey":"ecommerce.feature.product-bundles.product-bundles.740a","statedBy":null,"withheld":null},{"category":"production","checkGroupId":"bundle-743","criterionId":"743a","description":"a customer cannot replace a staff-created bundle through the application write","featureId":743,"featureName":"Bundle management authorization","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.bundle-integrity","points":3,"provenBy":null,"requiresFeatures":["ecommerce.feature.product-bundles"],"role":"guarantee","semantics":[{"do":"fill","text":"1.00"},{"action":"saveBundle","do":"callAction","from":"admin","input":{"attribute":"data-bundle-save-input","testid":"bundle-save"},"namedAction":{"args":["Protected bundle",1,"[{\"item\":\"Keyboard\",\"quantity\":1}]"],"id":"saveBundle","params":[{"in":"body","name":"name"},{"in":"body","name":"price"},{"in":"body","name":"componentsJson"}],"path":"/api/bundles","reducer":"save_bundle"}},{"do":"expectActionOutcome","outcome":"application-refused"},{"do":"reload"},{"do":"click","unlessVisible":"bundle-card"},{"do":"expectNumber","equals":75},{"attribute":"data-quantity","contains":"Keyboard","do":"expect","value":"2"}],"source":"scenarios/progression-product-bundles.json","stableKey":"ecommerce.spec.bundle-integrity.bundle-743.743a","statedBy":null,"withheld":null},{"category":"feature","checkGroupId":"promotion-checkout-active","criterionId":"621a","description":"an active promotion changes checkout and is recorded on the order","featureId":621,"featureName":"Bounded promotions at checkout","note":null,"packId":"ecommerce.progression.promotion-checkout","points":3,"provenBy":null,"role":"feature","semantics":[{"do":"click"},{"do":"click"},{"do":"fill","text":"LIVE10"},{"do":"click"},{"do":"click"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click"},{"do":"expectNumber","equals":8.9}],"source":"scenarios/progression-promotion-checkout.json","stableKey":"ecommerce.progression.promotion-checkout.promotion-checkout-active.621a","statedBy":"An active promotion applies to the cart and the order records its discount.","withheld":null},{"category":"feature","checkGroupId":"promotion-checkout-expired","criterionId":"621b","description":"an expired promotion is refused","featureId":621,"featureName":"Bounded promotions at checkout","note":null,"packId":"ecommerce.progression.promotion-checkout","points":2,"provenBy":null,"role":"feature","semantics":[{"do":"click"},{"do":"click"},{"do":"fill","text":"OLD10"},{"do":"click"},{"do":"expect"}],"source":"scenarios/progression-promotion-checkout.json","stableKey":"ecommerce.progression.promotion-checkout.promotion-checkout-expired.621b","statedBy":"Expired promotions cannot be applied.","withheld":null},{"category":"feature","checkGroupId":"promotion-checkout-exhausted","criterionId":"621c","description":"a fully redeemed promotion is refused","featureId":621,"featureName":"Bounded promotions at checkout","note":null,"packId":"ecommerce.progression.promotion-checkout","points":2,"provenBy":null,"role":"feature","semantics":[{"do":"click"},{"do":"click"},{"do":"fill","text":"ONCE10"},{"do":"click"},{"do":"click"},{"do":"click"},{"do":"click"},{"do":"fill","text":"ONCE10"},{"do":"click"},{"do":"expect"}],"source":"scenarios/progression-promotion-checkout.json","stableKey":"ecommerce.progression.promotion-checkout.promotion-checkout-exhausted.621c","statedBy":"A promotion cannot be used after its redemption limit is reached.","withheld":null},{"category":"feature","checkGroupId":"promotion-report-redemptions","criterionId":"622a","description":"the promotion report has the exact redemption count","featureId":622,"featureName":"Exact promotion totals","note":null,"packId":"ecommerce.progression.promotion-reporting","points":1,"provenBy":null,"role":"feature","semantics":[{"do":"expectNumber","equals":1}],"source":"scenarios/progression-promotion-reporting.json","stableKey":"ecommerce.progression.promotion-reporting.promotion-report-redemptions.622a","statedBy":"Promotion redemption counts match orders that used the promotion.","withheld":null},{"category":"feature","checkGroupId":"promotion-report-revenue","criterionId":"622b","description":"the promotion report has the exact discounted revenue","featureId":622,"featureName":"Exact promotion totals","note":null,"packId":"ecommerce.progression.promotion-reporting","points":2,"provenBy":null,"role":"feature","semantics":[{"do":"expectNumber","equals":80.1}],"source":"scenarios/progression-promotion-reporting.json","stableKey":"ecommerce.progression.promotion-reporting.promotion-report-revenue.622b","statedBy":"Promotion revenue after discounts matches orders that used the promotion.","withheld":null},{"category":"feature","checkGroupId":"promotion-rule-values","criterionId":"620a","description":"staff can save every bounded promotion value","featureId":620,"featureName":"Staff-managed promotion rules","note":null,"packId":"ecommerce.progression.promotion-rules","points":2,"provenBy":null,"role":"feature","semantics":[{"do":"click","unlessVisible":"promotion-code"},{"do":"fill","text":"SAVE10"},{"do":"fill","text":"10"},{"do":"fill","text":"2099-01-01"},{"do":"fill","text":"2099-12-31"},{"do":"fill","text":"2"},{"do":"click"},{"do":"expectNumber","equals":10},{"contains":"2099-01-01","do":"expect"},{"contains":"2099-12-31","do":"expect"},{"do":"expectNumber","equals":2}],"source":"scenarios/progression-promotion-rules.json","stableKey":"ecommerce.progression.promotion-rules.promotion-rule-values.620a","statedBy":"Staff can create a promotion code with a discount, active period, and redemption limit.","withheld":null},{"category":"production","checkGroupId":"promotion-management-boundary","criterionId":"620b","description":"customers cannot open promotion management","featureId":620,"featureName":"Staff-managed promotion rules","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"provenBy":null,"requiresFeatures":["ecommerce.progression.promotion-rules"],"role":"guarantee","semantics":[{"do":"click","unlessVisible":"promotion-code"},{"do":"fill","text":"ACCESS10"},{"do":"fill","text":"10"},{"do":"fill","text":"2099-01-01"},{"do":"fill","text":"2099-12-31"},{"do":"fill","text":"2"},{"do":"click"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"do":"click","ifAvailable":true,"unlessVisible":"promotion-code"},{"do":"click","unlessVisible":"promotion-code"},{"contains":"ACCESS10","do":"expect"},{"absent":true,"do":"expect"},{"do":"replayAs","from":"staff","match":"ACCESS10","namedAction":{"args":["ACCESS10",10,4070908800000000,4102444740000000,2],"id":"createPromotion","params":[{"in":"body","name":"code"},{"in":"body","name":"discountPercent"},{"in":"body","name":"startMicros"},{"in":"body","name":"endMicros"},{"in":"body","name":"usageLimit"}],"path":"/api/promotions","reducer":"create_promotion"},"swap":{"find":"ACCESS10","with":"HACK10"}},{"do":"expectReplayRejected"},{"absent":true,"contains":"HACK10","do":"expect"}],"source":"scenarios/progression-promotion-rules.json","stableKey":"ecommerce.spec.access-control.promotion-management-boundary.620b","statedBy":"Customers cannot manage promotion rules.","withheld":null},{"category":"feature","checkGroupId":"purchase-order","criterionId":"3c","description":"the purchase is recorded in the buyer's order history at the price paid","featureId":3,"featureName":"Purchase order history","note":null,"packId":"ecommerce.feature.purchasing","points":1,"provenBy":null,"role":"feature","semantics":[{"do":"click"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"contains":"Coffee Grinder","do":"expect"},{"do":"expectNumber","equals":64}],"source":"scenarios/progression-purchasing.json","stableKey":"ecommerce.feature.purchasing.purchase-order.3c","statedBy":"A purchase creates an order for the customer at the price paid.","withheld":null},{"category":"feature","checkGroupId":"recommendation-feedback","criterionId":"504a","description":"dismissing a recommendation removes it from the customer view","featureId":504,"featureName":"Recommendation dismissal","note":null,"packId":"ecommerce.progression.recommendation-feedback","points":2,"provenBy":null,"role":"feature","semantics":[{"absent":true,"contains":"Headphones","do":"expect"}],"source":"scenarios/progression-recommendation-feedback.json","stableKey":"ecommerce.progression.recommendation-feedback.recommendation-feedback.504a","statedBy":"Customers can dismiss a recommendation.","withheld":null},{"category":"production","checkGroupId":"recommendation-feedback-privacy","criterionId":"504b","description":"one customer's dismissal does not hide another customer's result","featureId":504,"featureName":"Recommendation dismissal","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"provenBy":null,"requiresFeatures":["ecommerce.progression.recommendation-feedback"],"role":"guarantee","semantics":[{"do":"waitUntilAbsent"},{"contains":"Headphones","do":"expect"}],"source":"scenarios/progression-recommendation-feedback.json","stableKey":"ecommerce.spec.access-control.recommendation-feedback-privacy.504b","statedBy":"Recommendation feedback belongs to one customer.","withheld":null},{"category":"production","checkGroupId":"recommendation-feedback-restart","criterionId":"504c","description":"a dismissed recommendation stays absent after reload and backend restart in a fresh browser","featureId":504,"featureName":"Recommendation dismissal","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.state-durability","points":2,"provenBy":null,"requiresFeatures":["ecommerce.progression.recommendation-feedback"],"role":"guarantee","semantics":[{"do":"reload"},{"do":"ensureSignedIn","name":"feedback-owner"},{"absent":true,"contains":"Headphones","do":"expect"},{"do":"restartBackend"},{"do":"freshClient"},{"do":"signIn","name":"feedback-owner"},{"do":"expect"},{"absent":true,"contains":"Headphones","do":"expect"}],"source":"scenarios/progression-recommendation-feedback.json","stableKey":"ecommerce.spec.state-durability.recommendation-feedback-restart.504c","statedBy":"A dismissed recommendation stays dismissed for that customer.","withheld":null},{"category":"production","checkGroupId":"review-eligibility-direct","criterionId":"618a","description":"the server refuses a review from a customer who did not buy the item","featureId":618,"featureName":"Review access","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.progression.review-access-specifications","points":2,"provenBy":null,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.reviews"],"role":"guarantee","semantics":[{"action":"submitReview","do":"callAction","from":"owner","input":{"attribute":"data-buy-input","contains":"Keyboard","testid":"item-card"},"namedAction":{"args":[0,5,"eligible progression review"],"id":"submitReview","method":"POST","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"},{"in":"body","name":"rating"},{"in":"body","name":"comment"}],"path":"/api/items/:id/reviews","reducer":"submit_review"}},{"do":"expectActionOutcome","outcome":"accepted"},{"do":"openItem","item":"Keyboard"},{"contains":"eligible progression review","do":"expect"},{"action":"submitReview","do":"callAction","from":"stranger","input":{"attribute":"data-buy-input","contains":"Keyboard","testid":"item-card"},"namedAction":{"args":[0,5,"never bought this"],"id":"submitReview","method":"POST","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"},{"in":"body","name":"rating"},{"in":"body","name":"comment"}],"path":"/api/items/:id/reviews","reducer":"submit_review"}},{"do":"expectActionOutcome","outcome":"application-refused","routeProvenBy":"owner"},{"do":"freshClient"},{"do":"signIn","name":"review-stranger"},{"do":"openItem","item":"Keyboard"},{"contains":"eligible progression review","do":"expect"},{"absent":true,"contains":"never bought this","do":"expect"}],"source":"scenarios/progression-review-access.json","stableKey":"ecommerce.progression.review-access-specifications.review-eligibility-direct.618a","statedBy":"Only a customer who bought an item can review it.","withheld":null},{"category":"production","checkGroupId":"stored-review-script","criterionId":"9180a","description":"review input is rejected or displayed without executing script in another customer session","featureId":9180,"featureName":"Stored review content","note":null,"observations":["unmentioned"],"packId":"ecommerce.progression.review-access-specifications","points":1,"provenBy":null,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.reviews"],"role":"guarantee","semantics":[{"action":"submitReview","do":"callAction","input":{"attribute":"data-buy-input","contains":"Keyboard","testid":"item-card"},"namedAction":{"args":[0,5,"Benign stored review"],"id":"submitReview","method":"POST","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"},{"in":"body","name":"rating"},{"in":"body","name":"comment"}],"path":"/api/items/:id/reviews","reducer":"submit_review"}},{"do":"expectActionOutcome","outcome":"accepted"},{"action":"submitReview","do":"callAction","input":{"attribute":"data-buy-input","contains":"Keyboard","testid":"item-card"},"namedAction":{"args":[0,5,"Stored review marker "],"id":"submitReview","method":"POST","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"},{"in":"body","name":"rating"},{"in":"body","name":"comment"}],"path":"/api/items/:id/reviews","reducer":"submit_review"}},{"do":"expectActionOutcome","outcome":"completed","routeProvenBy":"owner"},{"do":"openItem","item":"Keyboard"},{"contains":"Benign stored review","do":"expect"},{"do":"wait"},{"do":"expectNoScriptExecution"},{"do":"freshClient"},{"do":"signIn","name":"script-review-reader"},{"do":"armScriptCanary"},{"do":"openItem","item":"Keyboard"},{"contains":"Benign stored review","do":"expect"},{"do":"wait"},{"do":"expectNoScriptExecution"}],"source":"scenarios/progression-review-script.json","stableKey":"ecommerce.progression.review-access-specifications.stored-review-script.9180a","statedBy":null,"withheld":null},{"category":"production","checkGroupId":"search-ordering","criterionId":"402b","description":"active filters and text searches remain alphabetical after purchases; clearing them restores purchase ranking","featureId":402,"featureName":"Purchases preserve search ordering","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.search-ordering","points":1,"provenBy":null,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.progression.faceted-search"],"role":"guarantee","semantics":[{"do":"expectSequence","equals":["Air Purifier","Bluetooth Speaker","Coffee Grinder","Desk Lamp","Espresso Machine","Gaming Mouse","Headphones","Induction Cooktop","Keyboard","Laptop Stand"]},{"do":"fill","enter":true,"text":"e"},{"do":"fill","text":""},{"do":"click","ifAvailable":true},{"do":"expectSequence","equals":["Air Purifier","Bluetooth Speaker","Coffee Grinder","Desk Lamp","Espresso Machine","Gaming Mouse","Headphones","Keyboard","Mirrorless Camera","USB Cable"]},{"do":"fill","enter":true,"text":""},{"do":"expectSequence","equals":["Headphones","Air Purifier","Bluetooth Speaker","Coffee Grinder","Desk Lamp","Espresso Machine","Gaming Mouse","Induction Cooktop","Keyboard","Laptop Stand"]}],"source":"scenarios/progression-search-ordering.json","stableKey":"ecommerce.spec.search-ordering.search-ordering.402b","statedBy":"Active search and filter results use item-name order; clearing them restores purchase ranking","withheld":null},{"category":"production","checkGroupId":"shipping-accounting","criterionId":"202e","description":"shipping a purchased order does not deduct stock or add revenue again","featureId":202,"featureName":"Shipping preserves completed purchase accounting","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.progression.inventory-conservation-specifications","points":2,"provenBy":null,"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.warehouse-admin","ecommerce.progression.fulfilment-queue"],"role":"guarantee","semantics":[{"as":"stock-before-purchase","do":"dbRecordStock","item":"Keyboard"},{"as":"revenue-before-purchase","do":"recordNumber"},{"do":"click"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"do":"expect","ignoreCase":true,"value":"pending"},{"do":"dbExpectStock","item":"Keyboard","plus":-1,"relativeTo":"stock-before-purchase"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","ifAvailable":true},{"do":"expectNumber","plus":89,"relativeTo":"revenue-before-purchase"},{"as":"revenue-before-ship","do":"recordNumber"},{"as":"East-before-ship","do":"dbRecordStock","item":"Keyboard","warehouse":"East"},{"as":"West-before-ship","do":"dbRecordStock","item":"Keyboard","warehouse":"West"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"do":"click","ifAvailable":true},{"action":"ship","do":"callAction","from":"customer","input":{"attribute":"data-ship-input","contains":"Keyboard","testid":"order-item"},"namedAction":{"args":[0],"id":"ship","params":[{"in":"body","name":"orderId","wireType":"u64"}],"path":"/api/fulfilment/ship","reducer":"ship_order"}},{"do":"expectActionOutcome","outcome":"accepted"},{"do":"reload"},{"do":"ensureSignedIn","name":"shipping-accounting"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"do":"expect","ignoreCase":true,"value":"shipped"},{"do":"dbExpectStock","item":"Keyboard","plus":0,"relativeTo":"East-before-ship","warehouse":"East"},{"do":"dbExpectStock","item":"Keyboard","plus":0,"relativeTo":"West-before-ship","warehouse":"West"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","ifAvailable":true},{"do":"expectNumber","plus":0,"relativeTo":"revenue-before-ship"}],"source":"scenarios/progression-shipping-accounting.json","stableKey":"ecommerce.inventory-operations.shipping-accounting.202e","statedBy":"Shipping preserves the stock and revenue recorded for the purchase.","withheld":null},{"category":"production","checkGroupId":"signed-out-purchase","criterionId":"3a","description":"using the purchase control while signed out does not buy an item","featureId":3,"featureName":"Buying","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":1,"provenBy":null,"requiresFeatures":["ecommerce.feature.purchasing"],"role":"guarantee","semantics":[{"as":"keyboard-before-guest","do":"recordNumber"},{"do":"click","ifAvailable":true},{"do":"reload"},{"do":"click","ifAvailable":true},{"do":"click","ifAvailable":true},{"do":"expectNumber","plus":0,"relativeTo":"keyboard-before-guest"}],"source":"scenarios/progression-signed-out-purchase.json","stableKey":"ecommerce.spec.access-control.signed-out-purchase.3a","statedBy":"Unauthenticated callers cannot purchase.","withheld":null},{"category":"feature","checkGroupId":"split-tender-refunds-751","criterionId":"751a","description":"Full refund restores each original payment portion","featureId":751,"featureName":"Full refund restores each original payment portion","note":null,"packId":"ecommerce.feature.split-tender-refunds","points":2,"provenBy":null,"requiresFeatures":["ecommerce.feature.split-tender-refunds","ecommerce.feature.store-credit","ecommerce.progression.support-refunds"],"role":"feature","semantics":[{"do":"click"},{"do":"freshClient"},{"do":"signIn","name":"credit-owner-751"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click"},{"contains":"Desk Lamp","do":"expectElementCount","equals":1},{"do":"expectNumber","equals":42},{"do":"expectNumber","equals":10},{"do":"expectNumber","equals":32},{"do":"click"},{"attribute":"aria-busy","do":"expect","value":"false"},{"do":"expectNumber","equals":10}],"source":"scenarios/progression-split-tender-refunds.json","stableKey":"ecommerce.feature.split-tender-refunds.split-tender-refunds-751.751a","statedBy":null,"withheld":null},{"category":"production","checkGroupId":"production-756","criterionId":"756a","description":"Concurrent refunds restore the original credit and external amounts once, including after restart","featureId":756,"featureName":"Concurrent refunds do not duplicate credit after restart","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.split-tender-refunds","points":2,"provenBy":null,"requiresFeatures":["ecommerce.feature.split-tender-refunds","ecommerce.feature.store-credit","ecommerce.progression.support-refunds"],"role":"guarantee","semantics":[{"action":"supportRefund","do":"callConcurrently","from":"staff","input":{"attribute":"data-refund-input","contains":"Split refund 756","testid":"support-ticket"},"namedAction":{"args":[0],"id":"supportRefund","method":"POST","params":[{"in":"path","name":"caseId","placeholder":"{caseId}","wireType":"u64"}],"path":"/api/support/cases/{caseId}/refund","reducer":"support_refund"}},{"do":"expectCallOutcomes"},{"do":"freshClient"},{"do":"signIn","name":"credit-owner-756"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click"},{"contains":"Desk Lamp","do":"expectElementCount","equals":1},{"do":"expectNumber","equals":42},{"do":"expectNumber","equals":10},{"do":"expectNumber","equals":32},{"do":"click"},{"attribute":"aria-busy","do":"expect","value":"false"},{"do":"expectNumber","equals":10},{"do":"restartBackend"},{"do":"freshClient"},{"do":"signIn","name":"credit-owner-756"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click"},{"contains":"Desk Lamp","do":"expectElementCount","equals":1},{"do":"expectNumber","equals":42},{"do":"expectNumber","equals":10},{"do":"expectNumber","equals":32},{"do":"click"},{"attribute":"aria-busy","do":"expect","value":"false"},{"do":"expectNumber","equals":10}],"source":"scenarios/progression-split-tender-refunds.json","stableKey":"ecommerce.spec.split-tender-refunds.production-756.756a","statedBy":null,"withheld":null},{"category":"feature","checkGroupId":"staff-access","criterionId":"601a","description":"staff and administrators can sign in and open staff tools","featureId":601,"featureName":"Staff access","note":null,"packId":"ecommerce.progression.staff-access","points":2,"provenBy":null,"role":"feature","semantics":[{"do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"do":"click"},{"do":"expect"},{"do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click"},{"do":"expect"}],"source":"scenarios/progression-staff-access.json","stableKey":"ecommerce.progression.staff-access.staff-access.601a","statedBy":"Staff and administrators can sign in and use staff areas.","withheld":null},{"category":"production","checkGroupId":"staff-area-boundary","criterionId":"601b","description":"customers cannot open staff tools","featureId":601,"featureName":"Staff access","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"provenBy":null,"requiresFeatures":["ecommerce.progression.staff-access"],"role":"guarantee","semantics":[{"do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"do":"click"},{"do":"expect"},{"do":"signIn","exact":true,"name":"customer","password":"stackbench-customer-2026"},{"do":"click","ifAvailable":true},{"absent":true,"do":"expect"}],"source":"scenarios/progression-staff-access.json","stableKey":"ecommerce.spec.access-control.staff-area-boundary.601b","statedBy":"Customers cannot open staff tools.","withheld":null},{"category":"feature","checkGroupId":"staff-activity","criterionId":"624a","description":"an administrative change records its actor, action, subject, and time","featureId":624,"featureName":"Attributable staff activity","note":null,"packId":"ecommerce.progression.staff-activity","points":3,"provenBy":null,"role":"feature","semantics":[{"do":"click"},{"do":"click"},{"contains":"Activity Mug","do":"expect"},{"contains":"admin","do":"expect"},{"contains":"creat","do":"expect"},{"contains":"Activity Mug","do":"expect"},{"do":"expect"}],"source":"scenarios/progression-staff-activity.json","stableKey":"ecommerce.progression.staff-activity.staff-activity.624a","statedBy":"Each administrative change identifies its actor, action, subject, and time.","withheld":null},{"category":"production","checkGroupId":"staff-activity-privacy","criterionId":"624b","description":"customers cannot open staff activity history","featureId":624,"featureName":"Attributable staff activity","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"provenBy":null,"requiresFeatures":["ecommerce.progression.staff-activity"],"role":"guarantee","semantics":[{"absent":true,"do":"expect"}],"source":"scenarios/progression-staff-activity.json","stableKey":"ecommerce.spec.access-control.staff-activity-privacy.624b","statedBy":"Customers cannot open staff activity history.","withheld":null},{"category":"feature","checkGroupId":"staff-roles","criterionId":"621c","description":"an administrator can assign a staff role","featureId":621,"featureName":"Staff roles","note":null,"packId":"ecommerce.progression.staff-roles","points":1,"provenBy":null,"role":"feature","semantics":[{"do":"expect","value":"inventory"}],"source":"scenarios/progression-staff-roles.json","stableKey":"ecommerce.progression.staff-roles.staff-roles.621c","statedBy":"An administrator can assign a role to an existing staff account.","withheld":null},{"category":"production","checkGroupId":"staff-role-reload","criterionId":"621a","description":"an assigned staff role survives reload and backend restart in a fresh browser","featureId":621,"featureName":"Staff roles","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.state-durability","points":2,"provenBy":null,"requiresFeatures":["ecommerce.progression.staff-roles"],"role":"guarantee","semantics":[{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","ifAvailable":true,"unlessVisible":"staff-role-account-staff"},{"do":"expect","value":"inventory"},{"do":"restartBackend"},{"do":"freshClient"},{"do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","unlessVisible":"staff-role-account-staff"},{"do":"expect","value":"inventory"}],"source":"scenarios/progression-staff-roles.json","stableKey":"ecommerce.spec.state-durability.staff-role-reload.621a","statedBy":"Assigned staff roles persist.","withheld":null},{"category":"production","checkGroupId":"staff-role-boundary","criterionId":"621b","description":"a staff member cannot assign roles through the UI or a replayed request","featureId":621,"featureName":"Staff roles","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"provenBy":null,"requiresFeatures":["ecommerce.progression.staff-roles"],"role":"guarantee","semantics":[{"do":"reload"},{"do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"expect"},{"do":"click","unlessVisible":"staff-role-account-staff"},{"do":"fill","text":"staff"},{"do":"click"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","ifAvailable":true,"unlessVisible":"staff-role-account-staff"},{"do":"expect","value":"staff"},{"do":"reload"},{"do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"do":"click","ifAvailable":true},{"absent":true,"do":"expect"},{"do":"replayAs","from":"replayAdmin","match":"role","namedAction":{"args":[0,"inventory"],"id":"assignStaffRole","method":"PUT","params":[{"in":"path","name":"accountId","placeholder":":id","wireType":"u64"},{"in":"body","name":"role"}],"path":"/api/staff/:id/role","reducer":"assign_staff_role"},"namedTarget":{"attribute":"data-account-id","testid":"staff-role-account-staff","valueType":"string"},"swap":{"find":"\"role\":\"staff\"","with":"\"role\":\"inventory\""}},{"do":"expectReplayRejected"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","ifAvailable":true,"unlessVisible":"staff-role-account-staff"},{"do":"expect","value":"staff"}],"source":"scenarios/progression-staff-roles.json","stableKey":"ecommerce.spec.access-control.staff-role-boundary.621b","statedBy":"A staff member cannot assign or change roles.","withheld":null},{"category":"production","checkGroupId":"staff-role-revocation","criterionId":"621d","description":"removing administrator access blocks a previously authorized session without changing the target role","featureId":621,"featureName":"Staff roles","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"provenBy":null,"requiresFeatures":["ecommerce.progression.staff-roles"],"role":"guarantee","semantics":[{"do":"reload"},{"do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","unlessVisible":"staff-role-account-staff"},{"do":"replayAs","from":"roleAdmin","match":"__role-revocation-named-action__","namedAction":{"args":[0,"admin"],"id":"assignStaffRole","method":"PUT","params":[{"in":"path","name":"accountId","placeholder":":id","wireType":"u64"},{"in":"body","name":"role"}],"path":"/api/staff/:id/role","reducer":"assign_staff_role"},"namedTarget":{"attribute":"data-account-id","testid":"staff-role-account-staff","valueType":"string"}},{"do":"expectReplayCompleted","requireAccepted":true},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","ifAvailable":true,"unlessVisible":"staff-role-account-staff"},{"do":"expect","value":"admin"},{"do":"reload"},{"do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"do":"replayAs","from":"roleAdmin","match":"__role-revocation-named-action__","namedAction":{"args":[0,"admin"],"id":"assignStaffRole","method":"PUT","params":[{"in":"path","name":"accountId","placeholder":":id","wireType":"u64"},{"in":"body","name":"role"}],"path":"/api/staff/:id/role","reducer":"assign_staff_role"},"namedTarget":{"attribute":"data-account-id","testid":"staff-role-account-staff","valueType":"string"}},{"do":"expectReplayCompleted","requireAccepted":true},{"do":"replayAs","from":"roleAdmin","match":"__role-revocation-named-action__","namedAction":{"args":[0,"staff"],"id":"assignStaffRole","method":"PUT","params":[{"in":"path","name":"accountId","placeholder":":id","wireType":"u64"},{"in":"body","name":"role"}],"path":"/api/staff/:id/role","reducer":"assign_staff_role"},"namedTarget":{"attribute":"data-account-id","testid":"staff-role-account-staff","valueType":"string"}},{"do":"expectReplayCompleted","requireAccepted":true},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","ifAvailable":true,"unlessVisible":"staff-role-account-staff"},{"do":"expect","value":"staff"},{"do":"replayAs","from":"roleAdmin","match":"__role-revocation-named-action__","namedAction":{"args":[0,"admin"],"id":"assignStaffRole","method":"PUT","params":[{"in":"path","name":"accountId","placeholder":":id","wireType":"u64"},{"in":"body","name":"role"}],"path":"/api/staff/:id/role","reducer":"assign_staff_role"},"namedTarget":{"attribute":"data-account-id","testid":"staff-role-account-staff","valueType":"string"}},{"do":"expectReplayRejected"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","ifAvailable":true,"unlessVisible":"staff-role-account-staff"},{"do":"expect","value":"staff"}],"source":"scenarios/progression-staff-roles.json","stableKey":"ecommerce.spec.access-control.staff-role-revocation.621d","statedBy":"Only the admin role grants administrator access.","withheld":null},{"category":"feature","checkGroupId":"stock-alert-delivery","criterionId":"631c","description":"restored stock sends the requested alert","featureId":631,"featureName":"Stock alert delivery","note":null,"packId":"ecommerce.progression.stock-alerts","points":1,"provenBy":null,"requiresFeatures":["ecommerce.feature.warehouse-admin"],"role":"feature","semantics":[{"do":"freshClient"},{"do":"signIn","name":"stock-subscriber"},{"do":"click","unlessVisible":"notifications-panel"},{"attribute":"aria-busy","do":"expect","value":"false"},{"contains":"Air Purifier","do":"expectElementCount","equals":0},{"do":"click"},{"action":"restock","do":"callAction","input":{"attribute":"data-restock-input","contains":"Air Purifier","testid":"admin-location-row"},"namedAction":{"args":[0,0,1],"id":"restock","params":[{"in":"body","name":"itemId","wireType":"u64"},{"in":"body","name":"warehouseId","wireType":"u64"},{"in":"body","name":"quantity"}],"path":"/api/admin/restock","reducer":"admin_restock"}},{"do":"expectActionOutcome","outcome":"accepted"},{"do":"wait"},{"do":"freshClient"},{"do":"signIn","name":"stock-subscriber"},{"do":"click","unlessVisible":"notifications-panel"},{"attribute":"aria-busy","do":"expect","value":"false"},{"contains":"Air Purifier","do":"expect"}],"source":"scenarios/progression-stock-alert-delivery.json","stableKey":"ecommerce.progression.stock-alerts.stock-alert-delivery.631c","statedBy":"Show an alert when stock returns.","withheld":null},{"category":"production","checkGroupId":"stock-alert-deduplication","criterionId":"631a","description":"restored stock sends one alert and later restocks do not duplicate it","featureId":631,"featureName":"Private one-time stock alerts","note":"Sample a fresh account view 10 seconds after the second accepted restock. This catches persistent duplicates delivered by that sample, not all later or transient duplicates.","observations":["requested","unmentioned"],"packId":"ecommerce.spec.transactional-integrity","points":2,"provenBy":null,"requiresFeatures":["ecommerce.feature.warehouse-admin","ecommerce.progression.stock-alerts"],"role":"guarantee","semantics":[{"do":"freshClient"},{"do":"signIn","name":"stock-subscriber"},{"do":"click","unlessVisible":"notifications-panel"},{"attribute":"aria-busy","do":"expect","value":"false"},{"contains":"Air Purifier","do":"expectElementCount","equals":1},{"action":"restock","do":"callAction","input":{"attribute":"data-restock-input","contains":"Air Purifier","testid":"admin-location-row"},"namedAction":{"args":[0,0,1],"id":"restock","params":[{"in":"body","name":"itemId","wireType":"u64"},{"in":"body","name":"warehouseId","wireType":"u64"},{"in":"body","name":"quantity"}],"path":"/api/admin/restock","reducer":"admin_restock"}},{"do":"expectActionOutcome","outcome":"accepted"},{"do":"wait"},{"do":"freshClient"},{"do":"signIn","name":"stock-subscriber"},{"do":"click","unlessVisible":"notifications-panel"},{"attribute":"aria-busy","do":"expect","value":"false"},{"contains":"Air Purifier","do":"expectElementCount","equals":1}],"source":"scenarios/progression-stock-alerts.json","stableKey":"ecommerce.spec.transactional-integrity.stock-alert-deduplication.631a","statedBy":"A stock request creates one alert when stock returns.","withheld":null},{"category":"production","checkGroupId":"stock-alert-privacy","criterionId":"631b","description":"a customer who did not request the alert cannot see it","featureId":631,"featureName":"Private one-time stock alerts","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":1,"provenBy":null,"requiresFeatures":["ecommerce.feature.warehouse-admin","ecommerce.progression.stock-alerts"],"role":"guarantee","semantics":[{"do":"freshClient"},{"do":"signIn","name":"stock-subscriber"},{"do":"click","unlessVisible":"notifications-panel"},{"attribute":"aria-busy","do":"expect","value":"false"},{"contains":"Air Purifier","do":"expect"},{"do":"freshClient"},{"do":"signIn","name":"stock-other"},{"do":"click","unlessVisible":"notifications-panel"},{"attribute":"aria-busy","do":"expect","value":"false"},{"absent":true,"contains":"Air Purifier","do":"expect"}],"source":"scenarios/progression-stock-alerts.json","stableKey":"ecommerce.spec.access-control.stock-alert-privacy.631b","statedBy":"Stock alerts are private to the requesting customer.","withheld":null},{"category":"production","checkGroupId":"stock-limit","criterionId":"3d","description":"an item sells out visibly, and a further purchase is refused without changing stock","featureId":3,"featureName":"Buying","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.concurrency-safety","points":2,"provenBy":null,"requiresFeatures":["ecommerce.feature.purchasing"],"role":"guarantee","semantics":[{"do":"click"},{"do":"wait"},{"do":"click"},{"do":"wait"},{"do":"click"},{"do":"expectNumber","equals":0},{"do":"expect"},{"action":"buy","do":"callAction","input":{"attribute":"data-buy-input","contains":"Desk Lamp","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"}},{"do":"expectActionOutcome","outcome":"validation-refused"},{"do":"reload"},{"do":"ensureSignedIn","name":"eli"},{"do":"expectNumber","equals":0}],"source":"scenarios/progression-stock-limit.json","stableKey":"ecommerce.spec.concurrency-safety.stock-limit.3d","statedBy":"an item with zero stock cannot be bought","withheld":null},{"category":"feature","checkGroupId":"store-credit-750","criterionId":"750a","description":"Credit checkout records both payment portions","featureId":750,"featureName":"Credit checkout records both payment portions","note":null,"packId":"ecommerce.feature.store-credit","points":2,"provenBy":null,"role":"feature","semantics":[{"do":"click"},{"do":"freshClient"},{"do":"signIn","name":"credit-owner-750"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"contains":"Desk Lamp","do":"expectElementCount","equals":1},{"do":"expectNumber","equals":10},{"do":"expectNumber","equals":32},{"do":"expectNumber","equals":42},{"do":"click","unlessVisible":"credit-panel"},{"attribute":"aria-busy","do":"expect","value":"false"},{"do":"expectNumber","equals":0}],"source":"scenarios/progression-store-credit.json","stableKey":"ecommerce.feature.store-credit.store-credit-750.750a","statedBy":null,"withheld":null},{"category":"production","checkGroupId":"production-752","criterionId":"752a","description":"Repeating a grant reference does not increase the balance twice","featureId":752,"featureName":"Repeating a grant reference does not increase the balance twice","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.store-credit","points":2,"provenBy":null,"requiresFeatures":["ecommerce.feature.store-credit"],"role":"guarantee","semantics":[{"action":"grantCredit","do":"callAction","from":"staff","input":{"attribute":"data-action-input","overrides":{"accountId":{"actor":"owner","attribute":"data-account-id","testid":"credit-panel"}},"testid":"credit-grant"},"namedAction":{"args":[0,1000,""],"id":"grantCredit","method":"POST","params":[{"in":"body","name":"accountId","wireType":"u64"},{"in":"body","name":"amountMinor"},{"in":"body","name":"reference"}],"path":"/api/staff/credit","reducer":"grant_credit"}},{"do":"expectActionOutcome","outcome":"completed"},{"do":"freshClient"},{"do":"signIn","name":"credit-owner-752"},{"do":"click","unlessVisible":"credit-panel"},{"attribute":"aria-busy","do":"expect","value":"false"},{"do":"expectNumber","equals":10}],"source":"scenarios/progression-store-credit.json","stableKey":"ecommerce.spec.store-credit.production-752.752a","statedBy":null,"withheld":null},{"category":"production","checkGroupId":"production-753","criterionId":"753a","description":"A customer cannot grant credit","featureId":753,"featureName":"A customer cannot grant credit","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.store-credit","points":2,"provenBy":null,"requiresFeatures":["ecommerce.feature.store-credit"],"role":"guarantee","semantics":[{"do":"fill","text":"unauthorized-credit-753"},{"action":"grantCredit","do":"callAction","from":"staff","input":{"attribute":"data-action-input","overrides":{"accountId":{"actor":"owner","attribute":"data-account-id","testid":"credit-panel"}},"testid":"credit-grant"},"namedAction":{"args":[0,1000,""],"id":"grantCredit","method":"POST","params":[{"in":"body","name":"accountId","wireType":"u64"},{"in":"body","name":"amountMinor"},{"in":"body","name":"reference"}],"path":"/api/staff/credit","reducer":"grant_credit"}},{"do":"expectActionOutcome","outcome":"refused"},{"do":"freshClient"},{"do":"signIn","name":"credit-owner-753"},{"do":"click","unlessVisible":"credit-panel"},{"attribute":"aria-busy","do":"expect","value":"false"},{"do":"expectNumber","equals":10}],"source":"scenarios/progression-store-credit.json","stableKey":"ecommerce.spec.store-credit.production-753.753a","statedBy":null,"withheld":null},{"category":"production","checkGroupId":"production-754","criterionId":"754a","description":"Concurrent checkout consumes one cart and one credit allocation","featureId":754,"featureName":"Concurrent checkout consumes one cart and one credit allocation","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.store-credit","points":2,"provenBy":null,"requiresFeatures":["ecommerce.feature.store-credit"],"role":"guarantee","semantics":[{"action":"checkoutCredit","do":"callConcurrently","namedAction":{"args":[],"id":"checkoutCredit","method":"POST","path":"/api/checkout/credit","reducer":"checkout_credit"}},{"do":"expectCallOutcomes"},{"do":"freshClient"},{"do":"signIn","name":"credit-owner-754"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"contains":"Desk Lamp","do":"expectElementCount","equals":1},{"do":"expectNumber","equals":10},{"do":"expectNumber","equals":32},{"do":"expectNumber","equals":42},{"do":"click","unlessVisible":"credit-panel"},{"attribute":"aria-busy","do":"expect","value":"false"},{"do":"expectNumber","equals":0}],"source":"scenarios/progression-store-credit.json","stableKey":"ecommerce.spec.store-credit.production-754.754a","statedBy":null,"withheld":null},{"category":"production","checkGroupId":"production-755","criterionId":"755a","description":"Issued credit survives a backend restart","featureId":755,"featureName":"Issued credit survives a backend restart","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.store-credit","points":2,"provenBy":null,"requiresFeatures":["ecommerce.feature.store-credit"],"role":"guarantee","semantics":[{"do":"restartBackend"},{"do":"freshClient"},{"do":"signIn","name":"credit-owner-755"},{"do":"click","unlessVisible":"credit-panel"},{"attribute":"aria-busy","do":"expect","value":"false"},{"do":"expectNumber","equals":10}],"source":"scenarios/progression-store-credit.json","stableKey":"ecommerce.spec.store-credit.production-755.755a","statedBy":null,"withheld":null},{"category":"feature","checkGroupId":"subscriptions-760","criterionId":"760a","description":"A subscription creates exactly its requested deliveries and payments","featureId":760,"featureName":"A subscription creates exactly its requested deliveries and payments","note":null,"packId":"ecommerce.feature.subscriptions","points":2,"provenBy":null,"role":"feature","semantics":[{"do":"freshClient"},{"do":"signIn","name":"subscription-760"},{"do":"click","unlessVisible":"subscriptions-panel"},{"attribute":"aria-busy","do":"expect","value":"false"},{"do":"expect","value":"complete"},{"do":"expectElementCount","equals":2},{"do":"expectSequence","equals":["paid","paid"]},{"do":"expectNumber","equals":84},{"do":"dbExpectStock","equals":8,"item":"Desk Lamp"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click"},{"contains":"Desk Lamp","do":"expectElementCount","equals":2},{"do":"expectElementCount","equals":2}],"source":"scenarios/progression-subscriptions.json","stableKey":"ecommerce.feature.subscriptions.subscriptions-760.760a","statedBy":null,"withheld":null},{"category":"production","checkGroupId":"production-761","criterionId":"761a","description":"A pending subscription continues after backend restart without duplicate deliveries","featureId":761,"featureName":"A pending subscription continues after backend restart without duplicate deliveries","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.subscriptions","points":2,"provenBy":null,"requiresFeatures":["ecommerce.feature.subscriptions"],"role":"guarantee","semantics":[{"do":"restartBackend"},{"do":"freshClient"},{"do":"signIn","name":"subscription-761"},{"do":"click","unlessVisible":"subscriptions-panel"},{"attribute":"aria-busy","do":"expect","value":"false"},{"do":"expect","value":"complete"},{"do":"expectElementCount","equals":2},{"do":"expectSequence","equals":["paid","paid"]},{"do":"expectNumber","equals":84},{"do":"dbExpectStock","equals":8,"item":"Desk Lamp"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click"},{"contains":"Desk Lamp","do":"expectElementCount","equals":2},{"do":"expectElementCount","equals":2},{"do":"restartBackend"},{"do":"freshClient"},{"do":"signIn","name":"subscription-761"},{"do":"click","unlessVisible":"subscriptions-panel"},{"attribute":"aria-busy","do":"expect","value":"false"},{"do":"expect","value":"complete"},{"do":"expectElementCount","equals":2},{"do":"expectSequence","equals":["paid","paid"]},{"do":"expectNumber","equals":84},{"do":"dbExpectStock","equals":8,"item":"Desk Lamp"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click"},{"contains":"Desk Lamp","do":"expectElementCount","equals":2},{"do":"expectElementCount","equals":2}],"source":"scenarios/progression-subscriptions.json","stableKey":"ecommerce.spec.subscriptions.production-761.761a","statedBy":null,"withheld":null},{"category":"production","checkGroupId":"production-762","criterionId":"762a","description":"Another customer cannot cancel an active subscription","featureId":762,"featureName":"Another customer cannot cancel an active subscription","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.subscriptions","points":2,"provenBy":null,"requiresFeatures":["ecommerce.feature.subscriptions"],"role":"guarantee","semantics":[{"action":"cancelSubscription","do":"callAction","from":"owner","input":{"attribute":"data-action-input","testid":"subscription-cancel"},"namedAction":{"args":[0],"id":"cancelSubscription","method":"POST","params":[{"in":"path","name":"subscriptionId","placeholder":"{subscriptionId}","wireType":"u64"}],"path":"/api/subscriptions/{subscriptionId}/cancel","reducer":"cancel_subscription"}},{"do":"expectActionOutcome","outcome":"refused"},{"do":"expect","value":"active"},{"do":"click"},{"do":"freshClient"},{"do":"signIn","name":"subscription-762"},{"do":"click","unlessVisible":"subscriptions-panel"},{"attribute":"aria-busy","do":"expect","value":"false"},{"do":"expect","value":"cancelled"},{"as":"deliveries-at-cancel","count":true,"do":"recordNumber"},{"as":"stock-at-cancel","do":"dbRecordStock","item":"Desk Lamp"},{"do":"wait"},{"do":"expectElementCount","plus":0,"relativeTo":"deliveries-at-cancel"},{"do":"dbExpectStock","item":"Desk Lamp","plus":0,"relativeTo":"stock-at-cancel"}],"source":"scenarios/progression-subscriptions.json","stableKey":"ecommerce.spec.subscriptions.production-762.762a","statedBy":null,"withheld":null},{"category":"production","checkGroupId":"production-763","criterionId":"763a","description":"Pause survives a restart and resume completes the remaining deliveries","featureId":763,"featureName":"Pause survives a restart and resume completes the remaining deliveries","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.subscriptions","points":2,"provenBy":null,"requiresFeatures":["ecommerce.feature.subscriptions"],"role":"guarantee","semantics":[{"do":"click"},{"do":"expect","value":"paused"},{"do":"restartBackend"},{"do":"freshClient"},{"do":"signIn","name":"subscription-763"},{"do":"click","unlessVisible":"subscriptions-panel"},{"attribute":"aria-busy","do":"expect","value":"false"},{"do":"expect","value":"paused"},{"as":"deliveries-at-pause","count":true,"do":"recordNumber"},{"as":"stock-at-pause","do":"dbRecordStock","item":"Desk Lamp"},{"do":"wait"},{"do":"expectElementCount","plus":0,"relativeTo":"deliveries-at-pause"},{"do":"dbExpectStock","item":"Desk Lamp","plus":0,"relativeTo":"stock-at-pause"},{"do":"click"},{"do":"freshClient"},{"do":"signIn","name":"subscription-763"},{"do":"click","unlessVisible":"subscriptions-panel"},{"attribute":"aria-busy","do":"expect","value":"false"},{"do":"expect","value":"complete"},{"do":"expectElementCount","equals":2},{"do":"expectSequence","equals":["paid","paid"]},{"do":"expectNumber","equals":84},{"do":"dbExpectStock","equals":8,"item":"Desk Lamp"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click"},{"contains":"Desk Lamp","do":"expectElementCount","equals":2},{"do":"expectElementCount","equals":2}],"source":"scenarios/progression-subscriptions.json","stableKey":"ecommerce.spec.subscriptions.production-763.763a","statedBy":null,"withheld":null},{"category":"feature","checkGroupId":"support-history","criterionId":"612c","description":"the customer can view their support ticket history","featureId":612,"featureName":"Customer support history","note":null,"packId":"ecommerce.progression.support-history","points":1,"provenBy":null,"role":"feature","semantics":[{"do":"reload"},{"do":"ensureSignedIn","name":"support-owner"},{"do":"click","unlessVisible":"support-ticket"},{"contains":"Owner ticket {user:ticketmarker}","do":"expect"}],"source":"scenarios/progression-support-history.json","stableKey":"ecommerce.progression.support-history.support-history.612c","statedBy":"Signed-in customers can see their support ticket history.","withheld":null},{"category":"production","checkGroupId":"support-history-reload","criterionId":"612a","description":"support history survives reload and backend restart in a fresh browser","featureId":612,"featureName":"Customer support history","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.state-durability","points":2,"provenBy":null,"requiresFeatures":["ecommerce.progression.support-history"],"role":"guarantee","semantics":[{"do":"reload"},{"do":"ensureSignedIn","name":"support-owner"},{"do":"click"},{"contains":"Owner ticket {user:ticketmarker}","do":"expect"},{"do":"restartBackend"},{"do":"freshClient"},{"do":"signIn","name":"support-owner"},{"do":"click"},{"contains":"Owner ticket {user:ticketmarker}","do":"expect"}],"source":"scenarios/progression-support-history.json","stableKey":"ecommerce.spec.state-durability.support-history-reload.612a","statedBy":"A customer's support history persists.","withheld":null},{"category":"production","checkGroupId":"support-history-privacy","criterionId":"612b","description":"another customer neither sees nor receives the private ticket","featureId":612,"featureName":"Customer support history","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"provenBy":null,"requiresFeatures":["ecommerce.progression.support-history"],"role":"guarantee","semantics":[{"do":"reload"},{"do":"ensureSignedIn","name":"support-owner"},{"do":"click"},{"do":"fill","text":"owner@example.com"},{"do":"fill","text":"Private ticket {user:privateticketmarker}"},{"do":"fill","text":"Private account issue."},{"do":"click"},{"do":"expect","nonEmpty":true},{"do":"reload"},{"do":"ensureSignedIn","name":"support-owner"},{"do":"click"},{"contains":"Private ticket {user:privateticketmarker}","do":"expect"},{"contains":"Private ticket {user:privateticketmarker}","do":"expectReceived"},{"do":"reload"},{"do":"ensureSignedIn","name":"support-other"},{"do":"click"},{"absent":true,"contains":"Private ticket {user:privateticketmarker}","do":"expect"},{"contains":"Private ticket {user:privateticketmarker}","do":"expectNotReceived"}],"source":"scenarios/progression-support-history.json","stableKey":"ecommerce.spec.access-control.support-history-privacy.612b","statedBy":"Customers cannot see another customer's support tickets.","withheld":null},{"category":"production","checkGroupId":"support-history-logout","criterionId":"612d","description":"after logout the same browser storage no longer grants access to private support history","featureId":612,"featureName":"Customer support history","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":2,"provenBy":null,"requiresFeatures":["ecommerce.progression.support-history"],"role":"guarantee","semantics":[{"do":"reload"},{"do":"ensureSignedIn","name":"support-owner"},{"do":"click"},{"do":"fill","text":"owner@example.com"},{"do":"fill","text":"Logout ticket {user:logoutticketmarker}"},{"do":"fill","text":"Private account issue."},{"do":"click"},{"do":"expect","nonEmpty":true},{"do":"reload"},{"do":"ensureSignedIn","name":"support-owner"},{"do":"click","unlessVisible":"support-ticket"},{"contains":"Logout ticket {user:logoutticketmarker}","do":"expect"},{"contains":"Logout ticket {user:logoutticketmarker}","do":"expectReceived"},{"do":"reload"},{"do":"ensureSignedIn","name":"support-owner"},{"do":"click","unlessVisible":"signout"},{"do":"click"},{"do":"waitUntilAbsent"},{"do":"freshClient","preserveStorage":true},{"absent":true,"do":"expect"},{"do":"click"},{"do":"expect"},{"absent":true,"contains":"Logout ticket {user:logoutticketmarker}","do":"expect"},{"contains":"Logout ticket {user:logoutticketmarker}","do":"expectNotReceived"}],"source":"scenarios/progression-support-history.json","stableKey":"ecommerce.spec.access-control.support-history-logout.612d","statedBy":"Signed-out visitors cannot access private support tickets.","withheld":null},{"category":"feature","checkGroupId":"support-intake","criterionId":"610a","description":"a visitor can submit a support ticket and receives a reference","featureId":610,"featureName":"Support intake","note":null,"packId":"ecommerce.progression.support-intake","points":2,"provenBy":null,"role":"feature","semantics":[{"do":"click"},{"do":"fill","text":"visitor@example.com"},{"do":"fill","text":"Damaged package"},{"do":"fill","text":"The package arrived damaged."},{"do":"click"},{"do":"expect","nonEmpty":true}],"source":"scenarios/progression-support-intake.json","stableKey":"ecommerce.progression.support-intake.support-intake.610a","statedBy":"Anyone can open a support ticket and receives a reference.","withheld":null},{"category":"production","checkGroupId":"support-refund-access","criterionId":"615c","description":"a customer cannot issue a refund or change its records","featureId":615,"featureName":"Support refund access","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","points":1,"provenBy":null,"requiresFeatures":["ecommerce.progression.support-refunds"],"role":"guarantee","semantics":[{"absent":true,"do":"expect"},{"action":"supportRefund","authentication":"actor","do":"callAction","from":"staff","input":{"attribute":"data-action-input","testid":"support-refund"},"namedAction":{"args":[0],"id":"supportRefund","method":"POST","params":[{"in":"path","name":"caseId","placeholder":"{caseId}","wireType":"u64"}],"path":"/api/support/cases/{caseId}/refund","reducer":"support_refund"}},{"do":"expectActionOutcome","outcome":"refused"},{"do":"reload"},{"do":"ensureSignedIn","name":"refund-access-owner"},{"do":"click","ifAvailable":true},{"do":"click","unlessVisible":"support-subject"},{"do":"expect","notContains":"resolved"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click"},{"do":"expect","value":"pending"},{"absent":true,"contains":"Keyboard","do":"expect"}],"source":"scenarios/progression-support-refunds-access.json","stableKey":"ecommerce.spec.access-control.support-refund-access.615c","statedBy":"Only authorized staff can refund an order from a support case.","withheld":null},{"category":"production","checkGroupId":"support-refund-accounting","criterionId":"615b","description":"the refund equals the paid total, cannot be applied twice, and leaves another order unrefunded","featureId":615,"featureName":"Support refund accounting","note":null,"observations":["requested","unmentioned"],"packId":"ecommerce.spec.transactional-integrity","points":1,"provenBy":null,"requiresFeatures":["ecommerce.progression.support-refunds"],"role":"guarantee","semantics":[{"do":"click"},{"do":"reload"},{"do":"ensureSignedIn","name":"refund-accounting-owner"},{"do":"click","ifAvailable":true},{"do":"click","unlessVisible":"support-subject"},{"do":"expectNumber","plus":0,"relativeTo":"paid-total"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"do":"expectNumber","plus":0,"relativeTo":"paid-total"},{"contains":"Keyboard","do":"expectElementCount","equals":1},{"do":"replayAs","from":"staff","match":"refund","namedAction":{"args":[0],"id":"supportRefund","method":"POST","params":[{"in":"path","name":"caseId","placeholder":"{caseId}","wireType":"u64"}],"path":"/api/support/cases/{caseId}/refund","reducer":"support_refund"},"namedTarget":{"attribute":"data-entity-id","contains":"Accounting refund case","testid":"support-ticket","valueType":"string"}},{"do":"expectReplayCompleted"},{"do":"freshClient"},{"do":"signIn","name":"refund-accounting-owner"},{"do":"click"},{"do":"expectNumber","plus":0,"relativeTo":"paid-total"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"do":"expectNumber","plus":0,"relativeTo":"paid-total"},{"contains":"Keyboard","do":"expectElementCount","equals":1},{"do":"expectNumber","equals":0},{"contains":"Mouse","do":"expectElementCount","equals":0}],"source":"scenarios/progression-support-refunds-accounting.json","stableKey":"ecommerce.spec.transactional-integrity.support-refund-accounting.615b","statedBy":"The recorded refund equals the amount paid and is applied only once.","withheld":null},{"category":"feature","checkGroupId":"support-refunds-resolution","criterionId":"615a","description":"an authorized refund resolves the case and updates the order","featureId":615,"featureName":"Support refund resolution","note":null,"packId":"ecommerce.progression.support-refunds","points":2,"provenBy":null,"role":"feature","semantics":[{"do":"click"},{"contains":"resolved","do":"expect"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click"},{"contains":"refunded","do":"expect"}],"source":"scenarios/progression-support-refunds-resolution.json","stableKey":"ecommerce.progression.support-refunds.support-refunds-resolution.615a","statedBy":"Authorized staff can refund an order from its support case.","withheld":null},{"category":"production","checkGroupId":"return-refund-interaction","criterionId":"757a","description":"a support refund followed by physical return restores each warehouse once and refunds only the price paid","featureId":757,"featureName":"Return and support refund accounting","note":null,"packId":"ecommerce.feature.split-tender-refunds","points":2,"provenBy":null,"requiresFeatures":["ecommerce.l3.order-returns-features","ecommerce.progression.fulfilment-queue","ecommerce.progression.support-refunds"],"role":"feature","semantics":[{"do":"reload"},{"do":"ensureSignedIn","name":"return-refund-owner"},{"do":"click","ifAvailable":true},{"as":"757atotal","do":"dbRecordStock","item":"Keyboard"},{"as":"757aEast","do":"dbRecordStock","item":"Keyboard","warehouse":"East"},{"as":"757aWest","do":"dbRecordStock","item":"Keyboard","warehouse":"West"},{"as":"757arevenue","do":"recordNumber"},{"do":"click"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"do":"expect","ignoreCase":true,"value":"pending"},{"as":"757apaid","do":"recordNumber"},{"action":"ship","do":"callAction","from":"owner","input":{"attribute":"data-ship-input","contains":"Keyboard","testid":"order-item"},"namedAction":{"args":[0],"id":"ship","params":[{"in":"body","name":"orderId","wireType":"u64"}],"path":"/api/fulfilment/ship","reducer":"ship_order"}},{"do":"expectActionOutcome","outcome":"accepted"},{"do":"expect","ignoreCase":true,"value":"shipped"},{"do":"dbExpectStock","item":"Keyboard","plus":-1,"relativeTo":"757atotal"},{"do":"reload"},{"do":"ensureSignedIn","name":"return-refund-owner"},{"do":"click"},{"do":"fill","text":"Return refund 757a"},{"do":"fill","text":"Please refund this order."},{"do":"click"},{"contains":"Return refund 757a","do":"expect"},{"do":"click"},{"do":"click"},{"do":"expect"},{"action":"supportRefund","do":"callAction","from":"owner","input":{"attribute":"data-refund-input","contains":"Return refund 757a","testid":"support-ticket"},"namedAction":{"args":[0],"id":"supportRefund","method":"POST","params":[{"in":"path","name":"caseId","placeholder":"{caseId}","wireType":"u64"}],"path":"/api/support/cases/{caseId}/refund","reducer":"support_refund"}},{"do":"expectActionOutcome","outcome":"accepted"},{"do":"dbExpectStock","item":"Keyboard","plus":-1,"relativeTo":"757atotal"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"do":"click"},{"contains":"Keyboard","containsText":"returned","do":"expect","ignoreCase":true},{"do":"freshClient"},{"do":"signIn","name":"return-refund-owner"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click"},{"contains":"Keyboard","containsText":"returned","do":"expect","ignoreCase":true},{"do":"expectNumber","plus":0,"relativeTo":"757apaid"},{"do":"dbExpectStock","item":"Keyboard","plus":0,"relativeTo":"757aEast","warehouse":"East"},{"do":"dbExpectStock","item":"Keyboard","plus":0,"relativeTo":"757aWest","warehouse":"West"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","unlessVisible":"admin-revenue"},{"do":"expectNumber","plus":0,"relativeTo":"757arevenue"}],"source":"scenarios/progression-support-return-interaction.json","stableKey":"ecommerce.feature.split-tender-refunds.return-refund-interaction.757a","statedBy":null,"withheld":null},{"category":"production","checkGroupId":"return-refund-interaction","criterionId":"757b","description":"a physical return followed by support refund restores each warehouse once and refunds only the price paid","featureId":757,"featureName":"Return and support refund accounting","note":null,"packId":"ecommerce.feature.split-tender-refunds","points":2,"provenBy":null,"requiresFeatures":["ecommerce.l3.order-returns-features","ecommerce.progression.fulfilment-queue","ecommerce.progression.support-refunds"],"role":"feature","semantics":[{"do":"reload"},{"do":"ensureSignedIn","name":"return-refund-owner"},{"do":"click","ifAvailable":true},{"as":"757btotal","do":"dbRecordStock","item":"Desk Lamp"},{"as":"757bEast","do":"dbRecordStock","item":"Desk Lamp","warehouse":"East"},{"as":"757bWest","do":"dbRecordStock","item":"Desk Lamp","warehouse":"West"},{"as":"757brevenue","do":"recordNumber"},{"do":"click"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"do":"expect","ignoreCase":true,"value":"pending"},{"as":"757bpaid","do":"recordNumber"},{"action":"ship","do":"callAction","from":"owner","input":{"attribute":"data-ship-input","contains":"Desk Lamp","testid":"order-item"},"namedAction":{"args":[0],"id":"ship","params":[{"in":"body","name":"orderId","wireType":"u64"}],"path":"/api/fulfilment/ship","reducer":"ship_order"}},{"do":"expectActionOutcome","outcome":"accepted"},{"do":"expect","ignoreCase":true,"value":"shipped"},{"do":"dbExpectStock","item":"Desk Lamp","plus":-1,"relativeTo":"757btotal"},{"do":"reload"},{"do":"ensureSignedIn","name":"return-refund-owner"},{"do":"click"},{"do":"fill","text":"Return refund 757b"},{"do":"fill","text":"Please refund this order."},{"do":"click"},{"contains":"Return refund 757b","do":"expect"},{"do":"click"},{"do":"click"},{"do":"expect"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click","unlessVisible":"order-item"},{"do":"click"},{"contains":"Desk Lamp","containsText":"returned","do":"expect","ignoreCase":true},{"action":"supportRefund","do":"callAction","from":"owner","input":{"attribute":"data-refund-input","contains":"Return refund 757b","testid":"support-ticket"},"namedAction":{"args":[0],"id":"supportRefund","method":"POST","params":[{"in":"path","name":"caseId","placeholder":"{caseId}","wireType":"u64"}],"path":"/api/support/cases/{caseId}/refund","reducer":"support_refund"}},{"do":"expectActionOutcome","outcome":"accepted"},{"do":"freshClient"},{"do":"signIn","name":"return-refund-owner"},{"do":"click","ifAvailable":true,"unlessVisible":"order-item"},{"do":"click"},{"contains":"Desk Lamp","containsText":"returned","do":"expect","ignoreCase":true},{"do":"expectNumber","plus":0,"relativeTo":"757bpaid"},{"do":"dbExpectStock","item":"Desk Lamp","plus":0,"relativeTo":"757bEast","warehouse":"East"},{"do":"dbExpectStock","item":"Desk Lamp","plus":0,"relativeTo":"757bWest","warehouse":"West"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"click","unlessVisible":"admin-revenue"},{"do":"expectNumber","plus":0,"relativeTo":"757brevenue"}],"source":"scenarios/progression-support-return-interaction.json","stableKey":"ecommerce.feature.split-tender-refunds.return-refund-interaction.757b","statedBy":null,"withheld":null},{"category":"feature","checkGroupId":"support-assignment","criterionId":"611a","description":"staff can assign a new ticket","featureId":611,"featureName":"Support triage","note":null,"packId":"ecommerce.progression.support-triage","points":1,"provenBy":null,"role":"feature","semantics":[{"do":"fill","text":"staff"},{"do":"click"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"do":"click","ifAvailable":true,"unlessVisible":"support-assignee"},{"do":"click","ifAvailable":true,"unlessVisible":"support-assignee"},{"do":"expect","value":"staff"}],"source":"scenarios/progression-support-triage.json","stableKey":"ecommerce.progression.support-triage.support-assignment.611a","statedBy":"Staff can assign support tickets.","withheld":null},{"category":"feature","checkGroupId":"support-priority","criterionId":"611b","description":"staff can set a ticket priority","featureId":611,"featureName":"Support triage","note":null,"packId":"ecommerce.progression.support-triage","points":1,"provenBy":null,"role":"feature","semantics":[{"do":"fill","text":"high"},{"do":"click"},{"do":"reload"},{"do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"do":"click","ifAvailable":true,"unlessVisible":"support-assignee"},{"do":"click","ifAvailable":true,"unlessVisible":"support-assignee"},{"do":"expect","value":"high"}],"source":"scenarios/progression-support-triage.json","stableKey":"ecommerce.progression.support-triage.support-priority.611b","statedBy":"Staff can set support ticket priority.","withheld":null},{"category":"feature","checkGroupId":"support-status","criterionId":"611c","description":"staff can change a ticket status","featureId":611,"featureName":"Support triage","note":null,"packId":"ecommerce.progression.support-triage","points":1,"provenBy":null,"role":"feature","semantics":[{"do":"fill","text":"in progress"},{"do":"click"},{"contains":"in progress","do":"expect"}],"source":"scenarios/progression-support-triage.json","stableKey":"ecommerce.progression.support-triage.support-status.611c","statedBy":"Staff can change support ticket status.","withheld":null}],"schemaVersion":3,"task":{"baseMeaningSha256":null,"contracts":[{"id":"ecommerce.application-interface","owners":["recipe"],"text":"# Application interface\n\nUse each interface name below as an exact HTML attribute value. Use `id` for\na one-off element. Use `data-role` when the same interface can\nappear more than once. These attributes do not prescribe the layout, data\nmodel, libraries, or transport.\n\n\nFor error responses, use HTTP 401 or 403 for access errors and 400, 409, or 422 for input errors.\n\n\n\nReport reducer errors by failing the call.\n\n\nHuman-readable status text is case-insensitive. Machine identifiers and protocol values keep their specified spelling.\n"},{"id":"ecommerce.progression.staff-access-hooks","owners":["ecommerce.progression.staff-access"],"text":"## Staff access controls\n\nUse the existing account sign-in controls. Use `staff-link` for the staff area and `admin-link`\nfor the administrator area. Use `staff-area` for the staff tools, not for a loading or error message.\n\nUse these provided accounts:\n\n- staff: `staff` / `stackbench-staff-2026`\n- administrator: `admin` / `stackbench-admin-2026`\n- customer: `customer` / `stackbench-customer-2026`\n"},{"id":"ecommerce.progression.customer-profile-hooks","owners":["ecommerce.progression.customer-profile"],"text":"# Customer profile application interface\n\nUse `catalog-link` to return to the catalog. If a profile overlay blocks navigation,\nexpose `overlay-close` to dismiss it. Saving may leave the profile open.\n\nMake `profile-link` available from the catalog while signed in, without first opening another\narea. Use it to open the profile. Use `profile-name` and `profile-address` for the editable\nvalues. Use `profile-save` to save them. Use `profile-address-summary` to display\nthe saved address in the profile view.\n"},{"id":"ecommerce.progression.staff-role-hooks","owners":["ecommerce.progression.staff-roles"],"text":"# Staff role application interface\n\nPut role management in the administrator area opened by `admin-link`.\nUse `staff-role-row` for each staff account and set `data-account-id` to that account's server\nidentifier. Put `staff-role-select` and `staff-role-save` inside the row.\nAlso set the row's HTML `id` to `staff-role-account-` followed by\n`encodeURIComponent(username)`, using the exact account username without changing its case.\nFor example, username `staff` has row ID `staff-role-account-staff`. This identifies the\naccount independently of the role options or other text in the row.\n\nThe staff sign-in and staff-area controls come from the staff access feature.\n\nExpose the same role assignment used by `staff-role-save`.\n\n\nUse `PUT /api/staff/:id/role`, where `:id` is the account identifier from `data-account-id`.\nThe JSON body is `{ \"role\": \"\" }`.\n\n\n\nUse the `assign_staff_role` reducer with arguments in this order: `accountId: u64`,\n`role: string`. Render `data-account-id` as the decimal account identifier without precision loss.\n\n\n`staff-role-select` offers the roles `staff`, `inventory`, and `admin` as its option values.\n"},{"id":"ecommerce.progression.catalog-management-hooks","owners":["ecommerce.progression.catalog-management"],"text":"# Catalog management application interface\n\nUse `admin-link` to open the administrator area containing the product controls.\nUse `catalog-name`, `catalog-category`, `catalog-price`, and `catalog-variants` for the product\nvalues; `catalog-category` accepts a new category name as text, and `catalog-variants` accepts\ncomma-separated variant names. Use `catalog-save` to add the product. Use `item-variant` for each named variant shown\nto a visitor.\n"},{"id":"ecommerce.progression.payment-record-hooks","owners":["ecommerce.progression.payment-records"],"text":"# Payment record application interface\n\nUse `payment-record`, `payment-status`, and `payment-amount` inside the matching `order-item`.\n"},{"id":"ecommerce.progression.staff-activity-hooks","owners":["ecommerce.progression.staff-activity"],"text":"# Staff activity application interface\n\nUse `activity-link` to open staff activity history and `activity-entry` for each change. Inside\neach entry, use `activity-actor`, `activity-action`, `activity-subject`, and `activity-time`.\n"},{"id":"ecommerce.feature.catalog-items.hooks","owners":["ecommerce.feature.catalog-items"],"text":"# Catalog item application interface\n\n| Element ID | Required element |\n| --- | --- |\n| `item-list` | Contains the public catalog items. |\n| `item-card` | Shows one catalog item. |\n| `item-name` | Shows the item name inside its `item-card`; activating it opens `item-detail`. |\n| `item-price` | Shows the numeric item price inside its `item-card`. |\n| `item-stock` | Shows total stock inside its `item-card`. |\n| `item-detail` | Contains the selected item's details. |\n"},{"id":"ecommerce.feature.catalog-discovery.hooks","owners":["ecommerce.feature.catalog-discovery"],"text":"# Catalog discovery application interface\n\nNew catalog data starts with zero purchases. Do not seed sample orders or purchase counts.\nWhen adding this feature to an existing app, preserve purchases made through the app.\n\n| Element ID | Required element |\n| --- | --- |\n| `item-list` | Contains exactly the ten ranked storefront items. |\n| `item-card` | Shows one storefront or search result. |\n| `item-name` | Shows the item name inside its `item-card`. |\n| `search-input` | Searches the full catalog as the visitor types or when they press Enter; no separate control runs the search. |\n| `search-results` | Contains matching `item-card` results. |\n"},{"id":"ecommerce.l2.transfer-hooks","owners":["ecommerce.l2.stock-transfers-features"],"text":"# Stock transfer application interface\n\nPut `transfer-from`, `transfer-to`, `transfer-qty`, and `transfer-submit` inside the applicable\n`admin-item-row`. Use `warehouse-total` inside each `admin-warehouse-item` for its numeric stock\ntotal. Show `order-error` when a transfer is refused.\n\nPut `data-transfer-input` on each `admin-item-row`. Its value is a JSON object with exactly\n`itemId`, `fromWarehouseId`, and `toWarehouseId` for the currently selected source and destination.\nIdentifiers can be JSON numbers or strings.\n\n\nExpose `POST /api/admin/transfer`. The JSON body has `itemId`, `fromWarehouseId`,\n`toWarehouseId`, and `quantity`.\n\n\n\nExpose `admin_transfer_stock` with arguments in this order: `itemId: u64`,\n`fromWarehouseId: u64`, `toWarehouseId: u64`, `quantity`.\n\n"},{"id":"ecommerce.l2.price-hooks","owners":["ecommerce.l2.price-history-features"],"text":"# Price history application interface\n\nPut `price-input` and `price-submit` inside the applicable `admin-item-row`.\n\nPut a `data-price-input` attribute on each `admin-item-row`. Its value is a JSON object with\n`itemId` and numeric `price` from the current price input. Identifiers can be\nJSON numbers or strings.\n\n\nExpose `POST /api/admin/price`.\n\n\n\nExpose the `admin_change_price` reducer.\n\n\nUse the same action as the visible price control.\n"},{"id":"ecommerce.progression.price-history-order-hooks","owners":["ecommerce.progression.price-history-specifications"],"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.l2.price-history-features"],"text":"# Price history completed-order interface\n\nUse `orders-toggle`, `order-item`, and `order-total` to inspect the order created at checkout.\nUse `buy-now` inside an `item-card` to create a paid order before a price change.\n\n"},{"id":"ecommerce.progression.price-history-cart-hooks","owners":["ecommerce.progression.price-history-specifications"],"requiresFeatures":["ecommerce.feature.checkout","ecommerce.l2.price-history-features"],"text":"# Price history cart and checkout interface\n\nUse `add-to-cart` inside an `item-card`, `cart-toggle`, `cart-total`, and `checkout-submit`.\n"},{"id":"ecommerce.l2.inventory-dashboard-hooks","owners":["ecommerce.l2.inventory-dashboard"],"text":"# Inventory dashboard application interface\n\nUse `admin-link` to open the administrator area. If `low-stock-list` is on a separate screen\nwithin it, expose `low-stock-link` there to reach it. Use `low-stock-list` for items with 10 units\nor fewer and `low-stock-item` for each item. Use\n`buy-now` inside an `item-card` to create sales that change available stock.\n"},{"id":"ecommerce.l2.order-cancellation-hooks","owners":["ecommerce.l2.order-cancellation-features"],"text":"# Order cancellation application interface\n\nUse `order-status` for an order's state inside its `order-item`. Use `cancel-order` on a pending\norder. Use `catalog-link` to return to the catalog.\n`order-status` reads `pending` until the order ships, `shipped` once it has, and `cancelled`\nafter a cancellation. Later features may add further states after `shipped`.\n\nEach customer `order-item` must have `data-cancel-input` containing a JSON object with\nexactly `orderId`. Use the identifier representation required by the selected stack.\n\n\nUse `POST /api/orders/:id/cancel`.\n\n\n\nUse the `cancel_order` reducer.\n\n"},{"id":"ecommerce.l2.sales-dashboard-hooks","owners":["ecommerce.l2.sales-dashboard"],"text":"# Sales dashboard application interface\n\nOpen the administrator area with `admin-link`. If category totals are on a\nseparate tab or screen, expose `sales-link` there to open them. Omit this control\nwhen the totals are already shown.\n\nUse `category-row` for each product category, including a category with no sales yet, whose\nunits and revenue read 0. Use `category-units` and `category-revenue` inside each row. Use `recommended-list` for signed-out\nbest sellers and `recommended-item` for each item. Use `buy-now` inside an `item-card` to create\nsales activity for the dashboard. Each best seller contains its one-based `recommendation-rank`.\n"},{"id":"ecommerce.l2.recommendations-hooks","owners":["ecommerce.l2.recommendations"],"text":"# Recommendations application interface\n\nUse `recommended-list` for recommendations and `recommended-item` for each item in the list.\nUse `catalog-link` to open the catalog with this list visible.\n"},{"id":"ecommerce.feature.accounts.hooks","owners":["ecommerce.feature.accounts"],"text":"# Account application interface\n\nUse these exact `id` attributes on the corresponding visible controls. They do not prescribe UI\nstructure, data modeling, libraries, or implementation strategy.\n\nFrom the signed-out page, show the sign-up inputs, `signup-toggle`, or\n`signin-toggle`. If sign-up is inside the sign-in dialog, opening `signin-toggle`\nmust reveal the sign-up inputs or `signup-toggle`. That control must reveal the\nsign-up form. No other navigation is required to reach it.\nShow the sign-in inputs or `signin-toggle` on the signed-out page.\nWhile signed in, show `signout` directly or reveal it by clicking `current-user`.\nNo other navigation is required to reach sign-out.\n\n| Element ID | Observable element |\n|---|---|\n| `signup-username` | sign-up username input |\n| `signup-password` | sign-up password input |\n| `signup-submit` | sign-up submit control |\n| `signin-toggle` | control that reveals sign-in |\n| `signup-toggle` | reveals sign-up; available on the signed-out page or after opening `signin-toggle`; omit when sign-up inputs are already visible |\n| `signin-username` | sign-in username input |\n| `signin-password` | sign-in password input |\n| `signin-submit` | sign-in submit control |\n| `current-user` | Active account name, present only while signed in. Do not use this hook for a signed-out message. |\n| `signout` | sign-out control |\n| `auth-error` | visible account error |\n\nAccept any username of up to 48 characters made of letters, digits, and hyphens, and any\npassword of up to 64 characters.\n\nExpose the same account writes used by the UI.\n\nFor bearer-token authentication, expose `window.getSessionToken()` as a synchronous\nfunction that returns the current session's existing token, or `null` when signed out.\nThis hook does not prescribe credential storage. Return the caller's real credential;\ndo not create a separate identity.\n\n\nUse `POST /api/auth/signup` and `POST /api/auth/signin`. Both accept JSON with\n`username` and `password` fields.\n\n\n\nUse the `signUp` and `signIn` reducers. Both take `username` and `password`, in that order.\n\n"},{"id":"ecommerce.feature.purchasing.hooks","owners":["ecommerce.feature.purchasing"],"text":"# Purchasing application interface\n\nUse `catalog-link` to return to the catalog. Use `buy-now` inside an `item-card` to buy one unit. Use `orders-toggle` to open order history.\nIf an overlay blocks catalog navigation, expose a visible `overlay-close` control\nthat dismisses it before `catalog-link` is used. Screens without a blocking\noverlay need no such control. Dialogs, panels, and ordinary page layouts are all allowed.\nUse `order-item` for each order, containing the names of its purchased items. Inside that\n`order-item`, use `order-total` for its numeric total and `order-status` for its current state. Show `out-of-stock` inside an `item-card` once that item's stock reaches zero.\nUse `buy-error` for a failed purchase.\n\nPut `data-buy-input` on each `item-card`. Its value is a JSON object containing that item's\nserver identifier, for example `{\"itemId\":42}`. The identifier may be a JSON number or string.\nUse the same identifier for the visible buy action.\n\nExpose the same purchase used by `buy-now`.\n\n\nUse `POST /api/items/:id/buy`, where `:id` is the item identifier.\n\n\n\nUse the `buy_now` reducer with the item identifier.\n\n"},{"id":"ecommerce.feature.cart.hooks","owners":["ecommerce.feature.cart"],"text":"# Cart application interface\n\nUse `catalog-link` to return to the catalog. Use `add-to-cart` inside an `item-card` to add one unit. Use `cart-toggle` to open the cart.\nIf an overlay blocks catalog navigation, expose a visible `overlay-close` control\nthat dismisses it before `catalog-link` is used. Screens without a blocking\noverlay need no such control. Dialogs, panels, and ordinary page layouts are all allowed.\nUse `cart-count` for the total units, `cart-item` for each line, `cart-quantity` for its\nquantity, and `cart-total` for the numeric total. Use `cart-remove` to remove a line and\n`empty-cart` for an empty cart. Keep `cart-count` visible, showing 0, while the cart is empty.\n\nPut `data-buy-input` on each `item-card`. Its value is a JSON object containing that item's\nserver identifier, for example `{\"itemId\":42}`. Put `data-cart-input` on each `cart-item`.\nIts value contains the item identifier, for example `{\"itemId\":42}`. The identifier may be a\nJSON number or string.\n\nExpose the same add and quantity-update operations used by the cart controls.\n\n\nUse `POST /api/cart`. Put `itemId` in the JSON body.\nUse `PATCH /api/cart/:itemId`. Put `quantity` in the JSON body.\n\n\n\nUse the `add_to_cart` reducer with the item identifier.\nUse the `update_cart_quantity` reducer with the item identifier and quantity.\n\n\nUse `checkout-submit` to check out. Use `orders-toggle` to open order history and `order-item`\nfor each order created by checkout.\n"},{"id":"ecommerce.feature.checkout.hooks","owners":["ecommerce.feature.checkout"],"text":"# Checkout application interface\n\nUse `checkout-submit` to check out and `buy-error` for a failed checkout. Use `orders-toggle`\nto open order history and `order-item` for each order created by checkout.\n\nExpose the same checkout used by `checkout-submit`.\n\n\nUse `POST /api/checkout`.\n\n\n\nUse the `checkout` reducer.\n\n"},{"id":"ecommerce.orders.data","owners":["ecommerce.feature.checkout","ecommerce.feature.purchasing"],"text":"# Order data interface\n\nExpose the following data through the database's native read tools. These names\ndescribe a read interface; tables, collections, or database-native views over the\napplication's current records are allowed. Do not maintain separate copies for\nthis interface. Extra columns are allowed.\n\n- `item(id, name, price)` identifies catalog items and their current prices. These are the same items shown in the catalog.\n- `order_account(id, username)` identifies customer accounts. Do not include passwords or tokens in this interface.\n- `order_header(id, account_id, total, refunded, status)` contains every order from direct purchase or checkout, including cancelled orders. `total` is the amount booked for the order. `refunded` is the amount refunded so far, initially zero.\n- `order_line(id, order_id, item_id, quantity, unit_price)` contains each order's purchased lines and their booked unit prices.\n- When carts are available, `order_cart(account_id, item_id, quantity)` contains their current lines. An empty cart has no lines.\n- When carts and warehouse stock are available, `order_reservation(account_id, item_id, warehouse_id, quantity)` contains any stock held for those carts and already deducted from available `stock.quantity`. If the app does not hold stock for carts, this read interface is empty. This does not require adding stock reservations to the app.\n- When warehouse stock is available, `order_allocation(order_line_id, warehouse_id, quantity)` contains the original warehouse quantities used for each order line. Keep these quantities available after cancellation.\n\nEach `id` is a nonempty string or an exact nonnegative integer. Related identifiers\nrefer to that same `id`; a document may use `_id` when it has no `id`. Item and warehouse\nidentifiers match the existing `item` and `warehouse` data interfaces and the visible\napplication actions. Quantities are whole numbers. Money fields use the same currency\nunits as displayed prices, with at most two decimal places. Status uses the states in\nthe order interface.\n\nThe names and fields above must remain readable by the supplied database credentials\nas features are added. Customer screens and writes must use the same underlying records.\nThis does not require making customer data available to unauthenticated app users.\n"},{"id":"ecommerce.feature.reviews.hooks","owners":["ecommerce.feature.reviews"],"text":"# Review application interface\n\nOn item details, show the review form for eligible customers or expose\n`review-toggle` to open it. Omit this control when the form is already shown.\n\nUse `review-rating` on an input or select with values 1 through 5, `review-input` for the comment, and\n`review-submit` to submit it. Put the item's server identifier in\n`data-review-item-id` on `review-submit`. Use `review-average` for the numeric average,\n`review-item` for each visible review, and `review-error` for a failed submission.\n\nExpose the same review operation used by `review-submit`.\n\n\nUse `POST /api/items/:id/reviews`, where `:id` is the item identifier. Send `rating` and\n`comment` in the request body.\n\n\n\nUse the `submit_review` reducer with the item identifier, rating, and comment.\n\n"},{"id":"ecommerce.feature.warehouse-admin.hooks","owners":["ecommerce.feature.warehouse-admin"],"text":"# Warehouse administration application interface\n\nUse `admin-link` to open `admin-panel`. Use `admin-item-row` for each item and `admin-stock` for\nits numeric total stock. Use `admin-warehouse-item` for each warehouse. Use `admin-location-row`\nfor every item in every warehouse, including zero quantities; the row shows the item name and\nthe warehouse name, with\n`admin-location-qty` for its quantity. Use\n`restock-input` and `restock-submit` inside that row. Use `admin-revenue` for numeric total\nrevenue.\n\nKeep all item, warehouse, and holding rows available in the open admin panel, without pagination.\n\nPut a `data-restock-input` attribute on each `admin-location-row`. Its value is a JSON object\nwith exactly `itemId`, `warehouseId`, and a valid one-unit `quantity`. Identifiers can be JSON numbers or\nstrings.\n\nUse the same restock action as the visible control.\n\n## Stock data interface\n\nExpose singular tables `item(id, name, price)`, `warehouse(id, name)`, and\n`stock(item_id, warehouse_id, quantity)` for direct database access.\n`stock.item_id` and `stock.warehouse_id` reference `item.id` and `warehouse.id`; in a document\nstore they hold the referenced document's `id` value, or its `_id` when it has no `id`. Keep\nthese tables readable and writable with the database's own tools.\n\n\nExpose `POST /api/admin/restock`. The JSON body has the same fields as `data-restock-input`.\n\n\n\nExpose `admin_restock` with arguments in this order: `itemId: u64`, `warehouseId: u64`,\n`quantity`.\n\n"},{"id":"ecommerce.progression.support-history-hooks","owners":["ecommerce.progression.support-history"],"text":"## Customer support history controls\n\n`support-link` opens support. Use `support-ticket` for each ticket in the history, showing\nits subject. The intake form stays reachable from the same control.\n"},{"id":"ecommerce.progression.support-intake-hooks","owners":["ecommerce.progression.support-intake"],"text":"## Support intake controls\n\nUse `support-link` to open support. Use `support-email`, `support-subject`, and\n`support-message` for the ticket fields. Use `support-submit` to submit the ticket and\n`support-reference` to show its reference.\n"},{"id":"ecommerce.progression.support-triage-hooks","owners":["ecommerce.progression.support-triage"],"text":"## Support triage controls\n\nOpen the staff area with `staff-link`. If its ticket queue is on a separate tab or\nscreen, expose `support-queue-link` there to open it. Omit this control when the\neditable ticket controls are already shown.\n\nUse `support-ticket` for each ticket in the staff view. Within a ticket, use\n`support-assignee`, `support-priority`, and `support-status-input` for the editable fields.\nUse `support-update` to apply the changes. Use `support-status` to show the current status.\n`support-assignee` takes the assignee's username; if it is a select, its option values are the\nusernames. `support-priority` offers `low`, `normal`, and `high` as its option values.\n\n`support-status-input` offers the statuses `open`, `in progress`, and `resolved` as its option\nvalues; `support-status` shows the one chosen.\n"},{"id":"ecommerce.progression.fulfilment-queue-hooks","owners":["ecommerce.progression.fulfilment-queue"],"text":"# Fulfilment application interface\n\n| Element ID | Required element |\n| --- | --- |\n| `staff-link` | Opens the fulfilment area. |\n| `fulfilment-panel` | Contains fulfilment tools, including an empty queue; not a loading or error message. |\n| `queue-depth` | Shows the number of pending orders. |\n| `queue-item` | Shows one pending order and names its items. |\n| `queue-warehouse` | Shows the selected warehouse inside its `queue-item`. |\n| `ship-submit` | Marks the order in its `queue-item` as shipped. |\n\nOn `fulfilment-panel`, expose `data-submit-state` for the latest shipping submission:\n`idle` initially, `pending` immediately when submitted, `succeeded` only after the server\nconfirms success, or `failed` after rejection or transport failure. Keep the terminal state\non the panel when the shipped row disappears. A new submission must replace the old state.\n\n`order-status` reads `pending` until the order ships, `shipped` once it has, and `cancelled`\nafter a cancellation. Later features may add further states after `shipped`.\n\nEach customer `order-item` must have `data-ship-input` containing a JSON object with\nexactly `orderId`.\n\nUse the identifier representation required by the selected stack.\n\n\nUse `POST /api/fulfilment/ship` with `{ \"orderId\": ... }`.\n\n\n\nUse the `ship_order` reducer.\n\n"},{"id":"ecommerce.progression.promotion-rules-hooks","owners":["ecommerce.progression.promotion-rules"],"text":"# Promotion rule application interface\n\nUse `staff-link` to open the staff area. In that area, use `promotions-link` for promotion\nmanagement. Use `promotion-code`, `promotion-discount`,\n`promotion-start`, `promotion-end`, `promotion-limit`, and `promotion-submit` to create a rule.\nList rules as `promotion-item` elements and expose the saved values with the matching field IDs.\n\nExpose the same rule creation used by `promotion-submit`.\n\n\nUse `POST /api/promotions` with a JSON object containing `code` (string),\n`discountPercent` (number), `startMicros` and `endMicros` (integer numbers of microseconds\nsince the Unix epoch), and `usageLimit` (positive integer).\n\n\n\nUse the `create_promotion` reducer with arguments in this order: `code: string`,\n`discountPercent: f64`, `startMicros: i64`, `endMicros: i64`, `usageLimit: u32`.\nBoth time arguments are microseconds since the Unix epoch.\n\n\nOn a listed rule, `promotion-start` and `promotion-end` show the dates as entered, in ISO\n`YYYY-MM-DD` form.\n"},{"id":"ecommerce.progression.notification-preferences-hooks","owners":["ecommerce.progression.notification-preferences"],"text":"# Notification preference application interface\n\nSaving may leave settings open. Use `catalog-link` to return to the catalog. If\na settings overlay blocks navigation, expose `overlay-close` to dismiss it.\n\nMake `notification-settings` available from the catalog while signed in, without first opening another area. Use it to open the settings. Use `notification-order` and\n`notification-stock` for the choices, and `notification-save` to save them. Each choice exposes\nits current state in `data-state` as `on` or `off`.\nBoth choices start `off` for a new account. Activating `notification-order` or\n`notification-stock` switches it between `on` and `off`.\n"},{"id":"ecommerce.l3.reservation-hooks","owners":["ecommerce.l3.reservations-features"],"text":"# Reservation application interface\n\nUse `cart-reservation-timer` inside a `cart-item` for the remaining reservation time in seconds.\nUse `cart-item-expired` inside an expired cart line and `cart-expired-notice` after cart\nexpiration.\n"},{"id":"ecommerce.progression.managed-support-hooks","owners":["ecommerce.progression.managed-support"],"text":"# Managed support application interface\n\n## Managed support controls\n\nUse `support-ticket` for each case and set `data-entity-id` to that case's server identifier.\nWithin a case, use `support-status` for the current status, `support-reply` for the reply field,\n`support-reply-submit` to send a reply, and `support-reply-item` for each reply.\n\nExpose the same reply operation used by `support-reply-submit`.\n\n\nUse `POST /api/support/:id/replies`, where `:id` is the case identifier from `data-entity-id`.\nThe JSON body is `{ \"body\": \"\" }`.\n\n\n\nUse the `reply_support` reducer with arguments in this order: `ticketId: u64`, `body: string`.\nRender `data-entity-id` as the decimal case identifier without precision loss.\n\n"},{"id":"ecommerce.l3.scheduled-restock-hooks","owners":["ecommerce.l3.scheduled-restocks-features"],"text":"# Scheduled restock application interface\n\nUse `admin-link` to open the administrator area. If these controls are on a separate screen within\nit, expose `restocks-link` there to reach them. Use `schedule-restock-item`, `schedule-restock-warehouse`, `schedule-restock-qty`, and\n`schedule-restock-delay` for the inputs. Use `schedule-restock-submit` to schedule the restock.\nSet its `data-action-input` to a JSON object with exactly `item`, `warehouse`, `quantity`, and\n`delaySeconds`. `item` and `warehouse` are their names as strings; `quantity` and\n`delaySeconds` are JSON integers. Use `pending-restock-item` for each pending row and set its\n`data-entity-id` to the restock's server identifier, written as a decimal number.\nEach row contains the item name and sets `data-quantity` to its integer quantity. Use\n`pending-restock-remaining` for its remaining seconds, `pending-restock-cancel` to cancel it,\nand `stock-ledger-entry` for a completed stock movement.\n\n\nExpose `POST /api/admin/scheduled-restocks` and `DELETE /api/admin/scheduled-restocks/:id`.\nThe POST body has the same fields as `data-action-input`.\n\n\n\nExpose `schedule_restock` with arguments in this order: `item: string`, `warehouse: string`,\n`quantity: u32`, `delaySeconds: u32`; and `cancel_scheduled_restock` with `restockId: u64`.\n\n"},{"id":"ecommerce.l3.order-delivery-hooks","owners":["ecommerce.l3.order-delivery-features"],"text":"# Order delivery application interface\n\nUse `completed-order-item` for each completed order in the staff view. Use\n`completed-order-status` inside it for the current state. This extends the order lifecycle:\nafter `shipped`, `order-status` and `completed-order-status` read `delivered`.\n"},{"id":"ecommerce.l3.cart-expiration-hooks","owners":["ecommerce.l3.cart-expiration-features"],"text":"# Cart expiration application interface\n\nUse `cart-reservation-timer` inside a `cart-item` for the remaining reservation time in seconds.\nUse `cart-item-expired` inside an expired cart line and `cart-expired-notice` after cart\nexpiration.\n"},{"id":"ecommerce.progression.promotion-checkout-hooks","owners":["ecommerce.progression.promotion-checkout"],"text":"# Promotion checkout application interface\n\nUse `cart-promotion` for the code and `apply-promotion` to apply it. Use `promotion-error` when a\ncode is refused. Expose the saved discount as `order-discount` inside its `order-item`.\n"},{"id":"ecommerce.progression.stock-alert-hooks","owners":["ecommerce.progression.stock-alerts"],"text":"# Stock alert application interface\n\nUse `stock-alert` inside an unavailable `item-card` to request an alert. Use\n`notifications-toggle` to open notifications and `notification-item` for each alert.\nOn that `item-card`, expose `data-submit-state` for the latest stock-alert request:\n`idle` initially, `pending` immediately when submitted, `succeeded` only after the server\nconfirms success, or `failed` after rejection or transport failure. Keep the terminal state\nif the request button disappears. A new submission must replace the old state.\nUse `notifications-panel` for the opened notification view, including while its contents\nload. Set its `aria-busy` attribute to `false` only when the signed-in account's contents\nhave loaded successfully, including an empty list; keep it `true` while loading or after\na failed read. Its toggle may also close it.\nWithin a delivered stock alert, expose `stock-alert-delivery` containing the item's\ndisplayed name. A pending request must not expose `stock-alert-delivery`.\n\nUse `catalog-link` to return to the catalog. If an overlay blocks navigation,\nexpose a visible `overlay-close` control that dismisses it before navigation.\nScreens without a blocking overlay do not need this control.\n"},{"id":"ecommerce.l3.order-return-hooks","owners":["ecommerce.l3.order-returns-features"],"text":"# Order return application interface\n\nUse `return-item` inside an `order-item` for each item that can be returned. After a return,\nthe same `order-item` contains the word `returned`.\n\nEach ordinary item has an `order-line` containing its name, including while pending.\nSet `data-return-input` on that line to JSON with `orderId` and `itemId`, using the\nidentifiers accepted by the return action.\n\n\n`returnItem` is `POST /api/orders/{orderId}/items/{itemId}/return`.\n\n\n\n`returnItem` is `return_order_item(orderId, itemId)`.\n\n\nThe existing `orders-toggle`, `order-item`, `item-stock`, `admin-revenue`, and `catalog-link`\ninterfaces expose the order, stock, and accounting results.\n"},{"id":"ecommerce.progression.faceted-search-hooks","owners":["ecommerce.progression.faceted-search"],"text":"# Faceted search application interface\n\n| Element ID | Required element |\n| --- | --- |\n| `category-filter` | Sets the category filter; a text input, or a `select` whose option values are the category names. |\n| `minimum-price` | Sets the inclusive minimum price. |\n| `maximum-price` | Sets the inclusive maximum price. |\n| `in-stock-filter` | Toggles the in-stock-only filter, which starts off. |\n| `search-results` | Contains the filtered page; with no search text and no filter selected, the current page of the full catalog. |\n| `item-card` | Shows one result inside `search-results`. |\n| `search-next-page` | Opens the next page. |\n| `search-previous-page` | Opens the previous page. |\n\nIf a `filter-apply` control exists, activating it applies the filters; otherwise results update\nas each filter changes.\n\nSearch text or any active filter selects alphabetical ordering. With neither, use\npurchase ranking and break ties by item name. Clearing all search text and filters\nrestores purchase ranking. Both modes can use the same rendered list.\n"},{"id":"ecommerce.progression.order-support-hooks","owners":["ecommerce.progression.order-support"],"text":"# Order-linked support application interface\n\n## Order-linked support controls\n\nWithin a `support-ticket`, use `support-order-option` for each order that the customer can attach,\n`support-link-order` to attach the selected order, and `support-order` for the attached order. The\nlink action must expose its input in `data-action-input` for the named\n`linkSupportOrder` application action.\n\n\n`linkSupportOrder` is `POST /api/support/cases/{caseId}/order`.\n\n\n\n`linkSupportOrder` is the `link_support_order(caseId, orderId)` reducer.\n\n"},{"id":"ecommerce.progression.personalized-recommendation-hooks","owners":["ecommerce.progression.personalized-recommendations"],"text":"# Personalized recommendation application interface\n\nUse `recommendations` for the ordered recommendation list. Use `recommended-item` for each\nitem in that list. Each item contains its item name. Use `recommendation-rank` inside each item\nfor its one-based position in the list.\n"},{"id":"ecommerce.progression.promotion-reporting-hooks","owners":["ecommerce.progression.promotion-reporting"],"text":"# Promotion reporting application interface\n\nUse `promotions-link` to open the staff view. Use `promotion-report` for each promotion and\n`promotion-redemptions` and `promotion-revenue` for its totals.\n"},{"id":"ecommerce.feature.store-credit.interface","owners":["ecommerce.feature.store-credit"],"text":"# Store credit interface\n\nOpen customer credit with `credit-link`. The `credit-panel` exposes the signed-in account's `data-account-id` and `aria-busy=\"false\"` when loaded. Show `credit-balance` in major currency units and one `credit-entry` per movement.\n\nStaff use `credit-customer`, `credit-amount-input` (major units), `credit-reference-input`, and `credit-grant`. The grant control exposes `data-action-input` as JSON with `accountId`, `amountMinor`, and `reference`.\n\nUse `credit-checkout` in the cart. Each `order-item` shows `payment-credit-amount` and `payment-external-amount` in major units. Their sum is `payment-amount`.\n\n\n`grantCredit` is `POST /api/staff/credit` with `accountId`, `amountMinor`, and `reference`.\n`checkoutCredit` is `POST /api/checkout/credit` with no body fields.\n\n\n\n`grantCredit` is `grant_credit(accountId, amountMinor, reference)`.\n`checkoutCredit` is `checkout_credit()`.\n\n"},{"id":"ecommerce.feature.subscriptions.interface","owners":["ecommerce.feature.subscriptions"],"text":"# Subscription interface\n\nOpen with `subscriptions-link`. Use `subscription-item-input` (item name), `subscription-quantity-input`, `subscription-interval-input` (whole seconds, minimum 30), `subscription-deliveries-input` (1–12), and `subscription-create`.\n\nThe loaded `subscriptions-panel` has `aria-busy=\"false\"`. Each `subscription-row` includes the item name and `subscription-status`: `active`, `paused`, `cancelled`, or `complete`. Use `subscription-pause`, `subscription-resume`, and `subscription-cancel`; each exposes `data-action-input` with `subscriptionId`. Each processed slot has one `subscription-delivery` inside the row, with `subscription-delivery-status` (`paid` or `skipped`). `subscription-total` shows the sum of its recorded payments in major currency units. Ordinary orders and payment records include their item names.\n\n\n`pauseSubscription` is `POST /api/subscriptions/{subscriptionId}/pause`.\n`resumeSubscription` is `POST /api/subscriptions/{subscriptionId}/resume`.\n`cancelSubscription` is `POST /api/subscriptions/{subscriptionId}/cancel`.\n\n\n\n`pauseSubscription` is `pause_subscription(subscriptionId)`.\n`resumeSubscription` is `resume_subscription(subscriptionId)`.\n`cancelSubscription` is `cancel_subscription(subscriptionId)`.\n\n"},{"id":"ecommerce.progression.delivery-notification-hooks","owners":["ecommerce.progression.delivery-notifications"],"text":"# Delivery notification application interface\n\nUse `notifications-toggle` to open notifications. Use `notification-item` for each notification\nand `notification-unread-count` for the unread total.\n\nThe `notifications-panel` has `aria-busy=\"false\"` only when the signed-in account's\nnotifications have loaded. Keep the panel present when the list is empty.\n"},{"id":"ecommerce.progression.support-refund-hooks","owners":["ecommerce.progression.support-refunds"],"text":"# Support refund application interface\n\n## Support refund controls\n\nWithin a `support-ticket`, use `support-refund` for the refund action and\n`support-refund-total` for the recorded refund amount. The refund action must expose its input in\n`data-action-input` for the named `supportRefund` application action. The `support-ticket` also\nexposes the same JSON `{ \"caseId\": \"...\" }` in `data-refund-input` so the case remains addressable\nafter its refund button is disabled or removed. Within an `order-item`, use\n`order-refund-total` for the refunded amount and `refund-entry` for each refund record. Each\n`refund-entry` includes the order item name.\n\n\n`supportRefund` is `POST /api/support/cases/{caseId}/refund`.\n\n\n\n`supportRefund` is the `support_refund(caseId)` reducer.\n\n"},{"id":"ecommerce.progression.automatic-reorder-hooks","owners":["ecommerce.progression.automatic-reorder"],"text":"# Automatic reorder application interface\n\nUse these application interface names:\n\n- `reorder-link` opens the automatic reorder rules for warehouse staff.\n- `reorder-item`, `reorder-threshold`, and `reorder-quantity` identify the rule inputs.\n- `reorder-submit` saves the rule.\n- `reorder-rule-item` identifies each saved rule, sets `data-entity-id` to the rule's item\n identifier, and contains its item name, threshold, quantity, and current state.\n Set `data-threshold` and `data-quantity` to their integer values. Set\n `data-action-input` on `reorder-submit` to JSON with `itemId`, `threshold`, and `quantity`\n for the current form values.\n\nSaving a rule is the named `saveReorderRule` application action.\n\n\n`saveReorderRule` is `PUT /api/reorders/{itemId}` with `threshold` and `quantity` in the body.\n\n\n\n`saveReorderRule` is the `save_reorder_rule(itemId, threshold, quantity)` reducer.\n\n\nUse `buy-now` inside an `item-card` to create stock changes that evaluate a reorder rule.\n"},{"id":"ecommerce.progression.cart-recovery-hooks","owners":["ecommerce.progression.cart-recovery"],"text":"# Cart recovery application interface\n\nUse these application interface names:\n\n- `expired-cart` identifies the expired cart.\n- `restore-cart` restores that cart.\n- `cart-restore-warning` lists the names of items that could not be restored.\n\nThe existing `cart-item` control identifies each item restored to the active cart.\n"},{"id":"ecommerce.progression.recommendation-feedback-hooks","owners":["ecommerce.progression.recommendation-feedback"],"text":"# Recommendation feedback application interface\n\nUse `dismiss-recommendation` inside each `recommended-item`.\n"},{"id":"ecommerce.feature.split-tender-refunds.interface","owners":["ecommerce.feature.split-tender-refunds"],"text":"# Split refund interface\n\nReuse `support-refund` and its existing named action. Each `refund-entry` shows `refund-credit-amount` and `refund-external-amount` in major currency units. Show the restored credit in the existing credit balance and history.\n"},{"id":"ecommerce.interface.product-bundles","owners":["ecommerce.feature.product-bundles"],"text":"# Product bundle interface\n\nThe catalog has a `bundles-link`. The bundle panel contains `bundle-card` rows with\n`bundle-name`, numeric `bundle-price`, and `bundle-component` rows. Each component row has\n`bundle-component-name` and numeric `bundle-component-quantity`. Each component row also\nexposes its quantity in `data-quantity`.\n\nCatalog staff use `bundle-name-input`, `bundle-price-input` (currency units), and\n`bundle-components-input` (JSON array of `{ \"item\": \"product name\", \"quantity\": 1 }`),\nthen `bundle-save`. Saving an existing name edits that bundle. Each `bundle-card` exposes\n`data-bundle-input` as JSON `{ \"bundleId\": \"...\" }`.\nThe save button exposes `data-bundle-save-input` with `{ name, price, componentsJson }`\nfrom the current form values.\n\nUse the same application write for the visible form and this named action:\n\n\nSave a bundle with `POST /api/bundles` and `{ name, price, componentsJson }`.\n\n\n\nSave a bundle with `save_bundle(name: string, price: number, componentsJson: string)`.\n\n\nEach component uses an existing product's exact name. `componentsJson` contains the\ncomponent array as a JSON string.\n"},{"id":"ecommerce.interface.bundle-checkout","owners":["ecommerce.feature.bundle-checkout"],"text":"# Bundle checkout interface\n\nUse `bundle-add-to-cart` inside `bundle-card`. A bundle cart line uses the existing\n`cart-item`, `cart-reservation-timer`, and `cart-item-expired` interfaces, with\n`bundle-remove` to remove it. `checkout-submit` buys the cart through the existing checkout\naction. The existing `order-item` and `payment-amount` show the bundle name and price paid.\n\n\nAdd one bundle with `POST /api/cart/bundles` and `{ bundleId }`.\n\n\n\nAdd one bundle with `add_bundle_to_cart(bundleId: u64)`.\n\n\nUse the same application action as the visible control. The `data-bundle-input` attribute\nsupplies its bundle ID. The cart and order interfaces remain shared with individual products.\n"},{"id":"ecommerce.interface.bundle-returns","owners":["ecommerce.feature.bundle-returns"],"text":"# Bundle return interface\n\nUse `return-bundle` inside the existing `order-item`. Mark each returned bundle line\n`returned`. The order's `order-status` reads `returned` when all its lines have been\nreturned; otherwise keep its current fulfilment status. `bundle-refund-amount` shows\nthe refunded amount in currency units.\nEach bundle `order-item` exposes `data-bundle-return-input` as JSON `{ \"orderId\": \"...\" }`.\n\n\nReturn a whole bundle with `POST /api/bundle-orders/:orderId/return`.\n\n\n\nReturn a whole bundle with `return_bundle(orderId: u64)`.\n\n\nUse the same application action as the visible control.\n"}],"mode":"action","requirements":[{"id":"ecommerce.progression.fresh","owners":["recipe"],"text":"## New application\n\nBuild an ecommerce application from the product work below. Use `Storefront`\nas the visible page title. Use the application interface names where they are\nprovided. Start with no orders or purchase history.\n\n"},{"id":"ecommerce.progression.upgrade","owners":["recipe"],"text":"## Existing application\n\nAdd the current product work to the existing ecommerce application. Preserve its data;\ndo not add sample orders or purchase history while adding features.\n"},{"id":"ecommerce.l2.inventory-dashboard","owners":["ecommerce.l2.inventory-dashboard"],"text":"## Inventory dashboard\n\nGive administrators a low-stock view. It lists items with 10 units or fewer, most urgent first.\n"},{"id":"ecommerce.l2.sales-dashboard","owners":["ecommerce.l2.sales-dashboard"],"text":"## Sales dashboard\n\nGive customers and administrators sales views. Category totals show units sold and revenue for\neach category. Signed-out visitors see best sellers on the storefront.\n"},{"id":"ecommerce.l2.recommendations","owners":["ecommerce.l2.recommendations"],"text":"## Recommendations\n\nShow customers a recommended-for-you list on the catalog page. It recommends items from categories the customer has\nbought from and excludes items already in the cart.\n"},{"id":"ecommerce.feature.accounts.requirement","owners":["ecommerce.feature.accounts"],"text":"## Accounts\n\nVisitors can create an account with a username and password. Returning users can sign in with\nthose credentials, see which account is active, and sign out. Show a useful error for a taken\nusername or an incorrect password.\n"},{"id":"ecommerce.feature.catalog-items.requirement","owners":["ecommerce.feature.catalog-items"],"text":"## Catalog items\n\nShow public catalog items. Each item shows its name, price, and total stock.\n"},{"id":"ecommerce.feature.catalog-discovery.requirement","owners":["ecommerce.feature.catalog-discovery"],"text":"## Catalog discovery\n\nShow the ten most-purchased items. Break ties by item name. Search matches any part of\nan item name, without regard to case, across the full catalog.\n"},{"id":"ecommerce.feature.purchasing.requirement","owners":["ecommerce.feature.purchasing"],"text":"## Purchasing and orders\n\nA signed-in customer can buy one unit of an available item. The purchase reduces stock and\ncreates an order for that customer at the price paid. Their order history shows the newest\norders first, including items, quantities, prices, and totals.\n"},{"id":"ecommerce.feature.cart.requirement","owners":["ecommerce.feature.cart"],"text":"## Cart\n\nA signed-in customer has one cart. They can add an item, change its quantity, remove it, and\nsee the total. Adding the same item again increases the existing line quantity.\n"},{"id":"ecommerce.feature.checkout.requirement","owners":["ecommerce.feature.checkout"],"text":"## Checkout\n\nCheckout creates one order, reduces stock for every line, and empties the cart. Show an\nexplanation if checkout fails.\n"},{"id":"ecommerce.feature.reviews.requirement","owners":["ecommerce.feature.reviews"],"text":"## Reviews\n\nCustomers can rate items they purchased from one to five and add a comment. Show reviews\nand the average rating on the item detail.\n"},{"id":"ecommerce.feature.warehouse-admin.requirement","owners":["ecommerce.feature.warehouse-admin"],"text":"## Warehouse administration\n\nProvide an administration area that lists every item, both warehouses, and the quantity held in\neach warehouse. An administrator can add units to a selected item and warehouse. The area also\nshows total revenue across orders.\n"},{"id":"ecommerce.spec.access-control.purchasing","owners":["ecommerce.spec.access-control"],"requiresFeatures":["ecommerce.feature.purchasing"],"text":"## Access control: purchasing\n\nTreat identity as server-enforced authority, not UI decoration. Unauthenticated\ncallers cannot purchase, one account cannot place an order for another account,\nand order history is visible only to its owner. Knowing a username never grants\naccess to that account.\n\n"},{"id":"ecommerce.spec.access-control.warehouse-admin","owners":["ecommerce.spec.access-control"],"requiresFeatures":["ecommerce.feature.warehouse-admin"],"text":"## Access control: warehouse administration\n\nCustomer accounts cannot perform warehouse-administration writes. Enforce this\non the server even if the corresponding controls are hidden in the UI.\n\n"},{"id":"ecommerce.spec.access-control.reviews","owners":["ecommerce.spec.access-control"],"requiresFeatures":["ecommerce.feature.reviews"],"text":"## Access control: reviews\n\nOnly a customer who purchased an item may review it. Enforce this on the server\ninstead of relying on whether the review form is visible.\n\n"},{"id":"ecommerce.spec.access-control.cart","owners":["ecommerce.spec.access-control"],"requiresFeatures":["ecommerce.feature.cart"],"text":"## Access control: cart\n\nOne account cannot read or change another account's cart. Refuse a cart request\nwhose quantity is negative without changing state.\n\n"},{"id":"ecommerce.progression.staff-access","owners":["ecommerce.progression.staff-access"],"text":"## Staff access\n\nStaff and administrators can sign in and use staff areas.\n"},{"id":"ecommerce.spec.state-durability.accounts","owners":["ecommerce.spec.state-durability"],"requiresFeatures":["ecommerce.feature.accounts"],"text":"## State durability: accounts\n\nA signed-in session survives a page reload as the same account.\n\n"},{"id":"ecommerce.spec.state-durability.account-data","owners":["ecommerce.spec.state-durability"],"requiresFeatures":["ecommerce.feature.accounts","ecommerce.feature.cart"],"text":"## State durability: account data\n\nThe same account keeps its cart and orders across reload and connection loss.\nAfter reconnect it has current state without another sign-in. Restarting the\napplication must not duplicate starting data or reset state users changed.\n\n"},{"id":"ecommerce.spec.state-durability.checkout-crash","owners":["ecommerce.spec.state-durability"],"requiresFeatures":["ecommerce.feature.checkout"],"text":"After the application or database process restarts, an interrupted checkout leaves\neither its unchanged cart or one complete order with the cart cleared. A checkout\nreported as complete and the account's earlier orders remain recorded correctly.\nThe application can accept new checkouts after recovery.\n"},{"id":"ecommerce.progression.customer-profile","owners":["ecommerce.progression.customer-profile"],"text":"## Customer profile\n\nA signed-in customer can save and view their name and shipping address.\n"},{"id":"ecommerce.progression.support-intake","owners":["ecommerce.progression.support-intake"],"text":"## Support intake\n\nAnyone can open a support ticket with contact details, a subject, and a message. Return a\nreference that the visitor can use to identify the ticket.\n"},{"id":"ecommerce.spec.live-state.catalog-purchasing","owners":["ecommerce.spec.live-state"],"requiresFeatures":["ecommerce.feature.catalog-items","ecommerce.feature.purchasing"],"text":"## Live state: catalog and purchasing\n\nStock and best-seller ranking update every affected open storefront without a\nreload, including signed-out storefronts.\n\n"},{"id":"ecommerce.spec.live-state.cart","owners":["ecommerce.spec.live-state"],"requiresFeatures":["ecommerce.feature.cart"],"text":"## Live state: cart\n\nThe same account open in two clients sees one current cart; a change in either\nclient reaches the other without a reload.\n\n"},{"id":"ecommerce.spec.live-state.reviews","owners":["ecommerce.spec.live-state"],"requiresFeatures":["ecommerce.feature.reviews"],"text":"## Live state: reviews\n\nReviews and average ratings update affected open item views without a reload.\nA view opened while a review is submitted converges to the current review list.\n\n"},{"id":"ecommerce.spec.live-state.warehouse-admin","owners":["ecommerce.spec.live-state"],"requiresFeatures":["ecommerce.feature.catalog-items","ecommerce.feature.warehouse-admin"],"text":"## Live state: warehouse administration\n\nRestocking updates warehouse quantities, total item stock, and open storefronts\nwithout a reload.\n\n"},{"id":"ecommerce.progression.staff-roles","owners":["ecommerce.progression.staff-roles"],"text":"## Staff roles\n\nAn administrator can assign a role to an existing staff account. The `admin` role grants\nadministrator access. The `staff` and `inventory` roles grant staff access without\nadministrator access.\n"},{"id":"ecommerce.progression.catalog-management","owners":["ecommerce.progression.catalog-management"],"text":"## Catalog management\n\nAuthorized staff can add a product with named variants. The new product and its variants appear\nin the public catalog.\n"},{"id":"ecommerce.spec.concurrency-safety.purchasing","owners":["ecommerce.spec.concurrency-safety"],"requiresFeatures":["ecommerce.feature.purchasing"],"text":"## Concurrency safety: purchasing\n\nStock never becomes negative and only one customer can receive the last unit.\n\n"},{"id":"ecommerce.spec.concurrency-safety.restocking","owners":["ecommerce.spec.concurrency-safety"],"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.warehouse-admin"],"text":"## Concurrency safety: restocking\n\nConcurrent restocks and purchases preserve every accepted stock change.\n\n"},{"id":"ecommerce.spec.concurrency-safety.checkout","owners":["ecommerce.spec.concurrency-safety"],"requiresFeatures":["ecommerce.feature.checkout"],"text":"## Concurrency safety: checkout\n\nRepeating or racing checkout for the same cart creates only one order.\n\n"},{"id":"ecommerce.progression.payment-records","owners":["ecommerce.progression.payment-records"],"text":"## Payment records\n\nShow the payment status and amount paid on each order.\n"},{"id":"ecommerce.progression.staff-activity","owners":["ecommerce.progression.staff-activity"],"text":"## Staff activity history\n\nStaff can inspect a history of administrative changes. Each entry shows the staff member,\naction, subject, and time.\n"},{"id":"ecommerce.spec.transactional-integrity.reviews","owners":["ecommerce.spec.transactional-integrity"],"requiresFeatures":["ecommerce.feature.reviews"],"text":"## Transactional integrity: reviews\n\nA customer has at most one review per item. A later submission must not create\na duplicate; it may update the existing review or be refused.\n\n"},{"id":"ecommerce.spec.transactional-integrity.purchasing","owners":["ecommerce.spec.transactional-integrity"],"requiresFeatures":["ecommerce.feature.purchasing"],"text":"## Transactional integrity: purchasing\n\nThe server controls prices and order attribution rather than trusting client\nvalues. Historical order prices do not change.\n\n"},{"id":"ecommerce.spec.transactional-integrity.warehouse-accounting","owners":["ecommerce.spec.transactional-integrity"],"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.warehouse-admin"],"text":"## Transactional integrity: warehouse accounting\n\nEvery stock reduction caused by a sale has its matching order, revenue equals\nthe orders' recorded totals, and fresh clients agree with those results.\n\n"},{"id":"ecommerce.spec.external-data-sync.requirement","owners":["ecommerce.spec.external-data-sync"],"requiresFeatures":["ecommerce.feature.warehouse-admin"],"text":"## External data synchronization\n\nOther systems may write stock directly without calling the application. Open\npages and newly loaded pages must converge to a direct stock correction,\nincluding a correction made while the application server is down.\n"},{"id":"ecommerce.progression.fulfilment-queue","owners":["ecommerce.progression.fulfilment-queue"],"text":"# Fulfilment operations\n\nAdd a fulfilment area for staff and administrators. Show pending orders, their items, and the\nwarehouse that will ship them. Staff and administrators can mark an order as shipped. Show the\nnew status in the fulfilment area and the customer's order history.\n"},{"id":"ecommerce.l2.stock-transfer","owners":["ecommerce.l2.stock-transfers-features"],"text":"## Stock transfers\n\nAn administrator can move units of an item from one warehouse to another.\n"},{"id":"ecommerce.l2.order-cancellation","owners":["ecommerce.l2.order-cancellation-features"],"text":"## Order cancellation\n\nA customer can cancel an order before it ships. Refund the purchase, return its stock to\nthe supplying warehouse, and show its cancelled status in order history.\n"},{"id":"ecommerce.l2.price-history","owners":["ecommerce.l2.price-history-features"],"text":"## Price history\n\nAn administrator can change an item's price. Show the price in the public catalog.\n"},{"id":"ecommerce.progression.price-history-orders","owners":["ecommerce.progression.price-history-specifications"],"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.l2.price-history-features"],"text":"## Price history: completed orders\n\nCompleted orders keep the price paid at checkout. A later price change does not alter a receipt\nor revenue already recorded.\n\n"},{"id":"ecommerce.progression.price-history-cart-checkout","owners":["ecommerce.progression.price-history-specifications"],"requiresFeatures":["ecommerce.feature.checkout","ecommerce.l2.price-history-features"],"text":"## Price history: cart and checkout\n\nEvery open cart shows the new price without a reload. Checkout uses the current price.\n"},{"id":"ecommerce.progression.cancellation-queue","owners":["ecommerce.progression.cancellation-queue-specifications"],"requiresFeatures":["ecommerce.l2.order-cancellation-features","ecommerce.progression.fulfilment-queue"],"text":"## Fulfilment queue integration\n\nWhen fulfilment is available, cancelling a pending order also removes it from the fulfilment\nqueue.\n"},{"id":"ecommerce.progression.cancellation-accounting","owners":["ecommerce.progression.cancellation-accounting-specifications"],"requiresFeatures":["ecommerce.l2.order-cancellation-features"],"text":"## Cancellation accounting\n\nRevenue equals the sum of orders that remain paid. Cancellation removes the cancelled amount.\n\n"},{"id":"ecommerce.progression.support-triage","owners":["ecommerce.progression.support-triage"],"text":"## Support triage\n\nStaff can view new support tickets, assign a ticket, set its priority, and change its status.\n"},{"id":"ecommerce.progression.price-accounting","owners":["ecommerce.progression.price-accounting-specifications"],"requiresFeatures":["ecommerce.l2.price-history-features"],"text":"## Price accounting\n\nLater catalog price changes do not change the amount recorded on an existing order.\n"},{"id":"ecommerce.progression.support-history","owners":["ecommerce.progression.support-history"],"text":"## Customer support history\n\nSigned-in customers can see their support ticket history.\n"},{"id":"ecommerce.progression.promotion-rules","owners":["ecommerce.progression.promotion-rules"],"text":"## Promotion rules\n\nStaff can create promotion codes with a percentage discount, a start date, an end date, and a\nredemption limit.\n"},{"id":"ecommerce.progression.notification-preferences","owners":["ecommerce.progression.notification-preferences"],"text":"## Notification preferences\n\nSigned-in customers can turn order and stock notifications on or off.\n"},{"id":"ecommerce.progression.transfer-authorization","owners":["ecommerce.progression.operations-access-specifications"],"requiresFeatures":["ecommerce.l2.stock-transfers-features"],"text":"## Transfer authorization\n\nThe server allows only staff and administrators to transfer warehouse stock.\n"},{"id":"ecommerce.progression.price-authorization","owners":["ecommerce.progression.operations-access-specifications"],"requiresFeatures":["ecommerce.l2.price-history-features"],"text":"## Price authorization\n\nThe server allows only administrators to change catalog prices.\n"},{"id":"ecommerce.progression.shipping-authorization","owners":["ecommerce.progression.operations-access-specifications"],"requiresFeatures":["ecommerce.progression.fulfilment-queue"],"text":"## Shipping authorization\n\nThe server allows only staff and administrators to mark orders as shipped.\n"},{"id":"ecommerce.progression.order-ownership","owners":["ecommerce.progression.operations-access-specifications"],"requiresFeatures":["ecommerce.l2.order-cancellation-features"],"text":"## Order ownership\n\nThe server allows a customer to act only on that customer's own orders.\n"},{"id":"ecommerce.progression.review-access","owners":["ecommerce.progression.review-access-specifications"],"requiresFeatures":["ecommerce.feature.reviews"],"text":"## Review access\n\nOnly a customer who bought an item can review it.\n"},{"id":"ecommerce.progression.transfer-conservation","owners":["ecommerce.progression.inventory-conservation-specifications"],"requiresFeatures":["ecommerce.l2.stock-transfers-features"],"text":"## Stock conservation\n\nStock moves between warehouses without changing the total. A refused transfer changes nothing.\nWhen a purchase and a transfer overlap, the final total reflects the sold units exactly once.\n"},{"id":"ecommerce.progression.cancellation-conservation","owners":["ecommerce.progression.inventory-conservation-specifications"],"requiresFeatures":["ecommerce.l2.order-cancellation-features"],"text":"## Cancellation conservation\n\nCancelling an order restores its stock to the warehouse that supplied it. The restored total is\nthe same for current and newly opened clients.\n"},{"id":"ecommerce.l3.reservations","owners":["ecommerce.l3.reservations-features"],"text":"## Reservations\n\nAdding an item to a cart reserves its stock for 90 seconds. The cart shows the remaining time.\nCheckout consumes a live reservation. An expired reservation releases its stock and remains\nvisible as expired. Adding the item again renews the reservation.\n"},{"id":"ecommerce.l3.scheduled-restocks","owners":["ecommerce.l3.scheduled-restocks-features"],"text":"## Scheduled restocks\n\nAn admin can schedule and cancel a restock. Show pending restocks and their remaining\ntime. Show completed stock movements in a stock ledger.\n"},{"id":"ecommerce.l3.order-delivery","owners":["ecommerce.l3.order-delivery-features"],"text":"## Order delivery\n\nA shipped order becomes delivered 60 seconds after shipping. Show its status in the\ncustomer's order history and the staff view.\n"},{"id":"ecommerce.l3.cart-expiration","owners":["ecommerce.l3.cart-expiration-features"],"text":"## Cart expiration\n\nA cart with no activity for five minutes expires and releases its reservations. The customer\nsees an empty cart and an expiration notice.\n"},{"id":"ecommerce.l3.durable-reservations","owners":["ecommerce.l3.deferred-durability-specifications"],"requiresFeatures":["ecommerce.l3.reservations-features"],"text":"## Durable reservations\n\nPending reservations survive a backend restart.\n\n"},{"id":"ecommerce.progression.managed-support","owners":["ecommerce.progression.managed-support"],"text":"## Managed support cases\n\nCustomers and staff can exchange replies and update the status of a support case.\n"},{"id":"ecommerce.l3.durable-restocks","owners":["ecommerce.l3.deferred-durability-specifications"],"requiresFeatures":["ecommerce.l3.scheduled-restocks-features"],"text":"## Durable restocks\n\nPending restocks survive a backend restart.\n\n"},{"id":"ecommerce.l3.durable-order-delivery","owners":["ecommerce.l3.deferred-durability-specifications"],"requiresFeatures":["ecommerce.l3.order-delivery-features"],"text":"## Durable order delivery\n\nPending order delivery survives a backend restart.\n\n"},{"id":"ecommerce.l3.durable-cart-expiration","owners":["ecommerce.l3.deferred-durability-specifications"],"requiresFeatures":["ecommerce.l3.cart-expiration-features"],"text":"## Durable cart expiration\n\nPending cart expiration survives a backend restart.\n\n"},{"id":"ecommerce.l3.exactly-once-restocks","owners":["ecommerce.l3.deferred-integrity-specifications"],"requiresFeatures":["ecommerce.l3.scheduled-restocks-features"],"text":"## Exactly-once restocks\n\nRestarting the backend cannot apply a restock more than once.\n\n"},{"id":"ecommerce.l3.exactly-once-delivery","owners":["ecommerce.l3.deferred-integrity-specifications"],"requiresFeatures":["ecommerce.l3.order-delivery-features"],"text":"## Exactly-once delivery\n\nRestarting the backend cannot apply an order transition more than once.\n\n"},{"id":"ecommerce.l3.server-timed-restocks","owners":["ecommerce.l3.server-time-specifications"],"requiresFeatures":["ecommerce.l3.scheduled-restocks-features"],"text":"## Server-timed restocks\n\nA pending restock does not run early after a restart.\n\n"},{"id":"ecommerce.l3.server-timed-reservations","owners":["ecommerce.l3.server-time-specifications"],"requiresFeatures":["ecommerce.l3.reservations-features"],"text":"## Server-timed reservations\n\nA reservation expires without an open browser.\n\n"},{"id":"ecommerce.l3.deferred-access","owners":["ecommerce.l3.deferred-access-specifications"],"requiresFeatures":["ecommerce.l3.scheduled-restocks-features"],"text":"## Deferred-work access\n\nOnly an admin can schedule or cancel a restock.\n\n"},{"id":"ecommerce.l3.stock-conservation","owners":["ecommerce.l3.deferred-integrity-specifications"],"requiresFeatures":["ecommerce.l3.reservations-features"],"text":"## Stock conservation\n\nReservation expiry returns exactly the stock that the reservation took. Checkout does not take reserved stock twice.\n"},{"id":"ecommerce.progression.promotion-checkout","owners":["ecommerce.progression.promotion-checkout"],"text":"## Promotion checkout\n\nCustomers can apply an active promotion code to a cart. The final order records the applied\ndiscount. Expired and fully redeemed promotions are refused.\n"},{"id":"ecommerce.progression.stock-alerts","owners":["ecommerce.progression.stock-alerts"],"text":"## Stock alerts\n\nA signed-in customer can request an alert for an unavailable item. Show an alert when stock\nreturns.\n"},{"id":"ecommerce.progression.faceted-search","owners":["ecommerce.progression.faceted-search"],"text":"# Faceted search\n\nLet visitors filter the catalog by category, minimum price, maximum price, and availability.\nCombine the selected filters. While search text or any filter is active, order matching\nitems by name, with ten results per page. With no search text or active filter, use\nthe storefront's purchase ranking, breaking ties by item name. Clearing all search\ntext and filters returns to that ranking.\n"},{"id":"ecommerce.progression.personalized-recommendations","owners":["ecommerce.progression.personalized-recommendations"],"text":"# Personalized recommendations\n\nRecommend items from categories in the signed-in customer's purchase history. Exclude\nitems they already purchased. Order by global units sold, highest first, then by item name.\n"},{"id":"ecommerce.spec.search-ordering","owners":["ecommerce.spec.search-ordering"],"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.progression.faceted-search"],"text":"# Search ordering after purchases\n\nPurchases must not change the alphabetical order of active search or filter results.\nClearing all search text and filters restores the current purchase ranking.\n"},{"id":"ecommerce.l3.order-returns","owners":["ecommerce.l3.order-returns-features"],"text":"## Order returns\n\nA customer can return an item after the order ships for a refund of its purchase price.\nRestock the item and mark it returned in order history.\n"},{"id":"ecommerce.progression.order-support","owners":["ecommerce.progression.order-support"],"text":"## Order-linked support\n\nA customer can attach an order to a support case. Staff can inspect the linked order\nfrom the case.\n"},{"id":"ecommerce.progression.promotion-reporting","owners":["ecommerce.progression.promotion-reporting"],"text":"## Promotion reporting\n\nStaff can see each promotion's redemption count and revenue after discounts.\n"},{"id":"ecommerce.progression.delivery-notifications","owners":["ecommerce.progression.delivery-notifications"],"text":"## Delivery notifications\n\nNotify customers when their orders are delivered, using their notification preferences.\n"},{"id":"ecommerce.progression.automatic-reorder","owners":["ecommerce.progression.automatic-reorder"],"text":"# Automatic reorder rules\n\nWarehouse staff can manage automatic reorder rules. A rule names an item, a stock\nthreshold, and a restock quantity. Schedule a restock when stock falls from above the\nthreshold to the threshold or below.\nThe automatic restock is due 60 seconds after it is scheduled.\n"},{"id":"ecommerce.progression.cart-recovery","owners":["ecommerce.progression.cart-recovery"],"text":"# Cart recovery\n\nLet a signed-in customer restore an expired cart. Reserve each item again only when its full\nquantity is available. Restore the available items and list each item that could not be restored.\n"},{"id":"ecommerce.progression.recommendation-feedback","owners":["ecommerce.progression.recommendation-feedback"],"text":"## Recommendation feedback\n\nA customer can dismiss a recommendation from their list.\n"},{"id":"ecommerce.feature.store-credit","owners":["ecommerce.feature.store-credit"],"text":"## Store credit\n\nStaff can issue customer credit with a reference. Customers can see their balance and history and choose credit at cart checkout. Use credit first, up to the order total; record any remainder as the existing payment. Amounts use the shop currency and whole minor units. A reference identifies one grant.\n"},{"id":"ecommerce.feature.subscriptions","owners":["ecommerce.feature.subscriptions"],"text":"## Scheduled purchases\n\nCustomers can subscribe to an individual catalog item (not a bundle) and quantity for a chosen number of deliveries at a chosen interval. Use the item price at subscription creation. The first delivery is due after one interval. Each delivery creates an ordinary order and payment. Skip an unavailable delivery without charging; it still uses one delivery slot. Customers can pause, resume, or cancel future deliveries; a pause moves future due times by the pause duration.\n"},{"id":"ecommerce.progression.support-refunds","owners":["ecommerce.progression.support-refunds"],"text":"## Support refunds\n\nStaff can refund an entire order from its support case. A successful refund resolves\nthe case. Show the refund amount and case status.\n\nA refund does not prevent a later physical return of shipped goods. Refund only\nthe amount not already refunded, and restock goods when they are returned.\n"},{"id":"ecommerce.spec.access-control.automatic-reorder-access","owners":["ecommerce.spec.access-control"],"requiresFeatures":["ecommerce.progression.automatic-reorder"],"text":"## automatic-reorder-access\n\nOnly warehouse staff can manage automatic reorder rules.\n\n"},{"id":"ecommerce.spec.access-control.recommendation-profile-isolation","owners":["ecommerce.spec.access-control"],"requiresFeatures":["ecommerce.progression.personalized-recommendations"],"text":"## recommendation-profile-isolation\n\nCustomer recommendation profiles are isolated.\n\n"},{"id":"ecommerce.spec.access-control.staff-activity-privacy","owners":["ecommerce.spec.access-control"],"requiresFeatures":["ecommerce.progression.staff-activity"],"text":"## staff-activity-privacy\n\nCustomers cannot open staff activity history.\n\n"},{"id":"ecommerce.spec.access-control.order-support-ownership","owners":["ecommerce.spec.access-control"],"requiresFeatures":["ecommerce.progression.order-support"],"text":"## order-support-ownership\n\nA customer cannot attach or inspect another customer's order.\n\n"},{"id":"ecommerce.spec.access-control.delivery-notification-privacy","owners":["ecommerce.spec.access-control"],"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.progression.delivery-notifications","ecommerce.progression.fulfilment-queue"],"text":"## delivery-notification-privacy\n\nDelivery notifications are private to the order owner.\n\n"},{"id":"ecommerce.spec.access-control.support-refund-access","owners":["ecommerce.spec.access-control"],"requiresFeatures":["ecommerce.progression.support-refunds"],"text":"## support-refund-access\n\nOnly authorized staff can refund an order from a support case.\n\n"},{"id":"ecommerce.spec.access-control.recommendation-feedback-privacy","owners":["ecommerce.spec.access-control"],"requiresFeatures":["ecommerce.progression.recommendation-feedback"],"text":"## recommendation-feedback-privacy\n\nRecommendation feedback belongs to one customer.\n\n"},{"id":"ecommerce.spec.state-durability.recommendation-feedback-restart","owners":["ecommerce.spec.state-durability"],"requiresFeatures":["ecommerce.progression.recommendation-feedback"],"text":"## recommendation-feedback-restart\n\nDismissed recommendations stay dismissed after reconnecting or restarting the server.\n\n"},{"id":"ecommerce.spec.transactional-integrity.automatic-reorder-deduplication","owners":["ecommerce.spec.transactional-integrity"],"requiresFeatures":["ecommerce.feature.purchasing","ecommerce.progression.automatic-reorder"],"text":"## automatic-reorder-deduplication\n\nA pending automatic restock is not scheduled twice.\n\n"},{"id":"ecommerce.spec.transactional-integrity.payment-deduplication","owners":["ecommerce.spec.transactional-integrity"],"requiresFeatures":["ecommerce.progression.payment-records"],"text":"## payment-deduplication\n\nA checkout does not create duplicate payments.\n\n"},{"id":"ecommerce.spec.transactional-integrity.support-refund-accounting","owners":["ecommerce.spec.transactional-integrity"],"requiresFeatures":["ecommerce.progression.support-refunds"],"text":"## support-refund-accounting\n\nThe recorded refund equals the amount paid and is applied only once.\n"},{"id":"ecommerce.feature.split-tender-refunds","owners":["ecommerce.feature.split-tender-refunds"],"text":"## Refunds with store credit\n\nExtend support refunds and item returns to orders paid with credit and another payment. Return each part to its original source. A full refund restores the original credit portion to the customer balance and refunds the original external portion.\n"},{"id":"ecommerce.spec.bundle-integrity.product-bundles","owners":["ecommerce.spec.bundle-integrity"],"requiresFeatures":["ecommerce.feature.product-bundles"],"text":"## Product bundles\n\nOnly authorized staff can change bundles.\n\n"},{"id":"ecommerce.spec.bundle-integrity.bundle-checkout","owners":["ecommerce.spec.bundle-integrity"],"requiresFeatures":["ecommerce.feature.bundle-checkout"],"text":"## Bundle checkout\n\nReserve all components or none. Competing purchases share the same stock. Release component reservations when the cart expires or the bundle is removed.\n\n"},{"id":"ecommerce.spec.bundle-integrity.bundle-returns","owners":["ecommerce.spec.bundle-integrity"],"requiresFeatures":["ecommerce.feature.bundle-returns"],"text":"## Bundle returns\n\nReturn the original component allocations and price paid. Repeating a return must not change stock or refunds again. Customers cannot return another account's order.\n\n"},{"id":"ecommerce.spec.store-credit.store-credit","owners":["ecommerce.spec.store-credit"],"requiresFeatures":["ecommerce.feature.store-credit"],"text":"## Store credit\n\nOnly authorized staff can grant credit. Repeating a reference must not issue credit twice. Concurrent checkout must not duplicate the order or credit use. Accepted credit survives a backend restart.\n\n"},{"id":"ecommerce.spec.split-tender-refunds.split-tender-refunds","owners":["ecommerce.spec.split-tender-refunds"],"requiresFeatures":["ecommerce.feature.split-tender-refunds"],"text":"## Split-tender refunds\n\nConcurrent or repeated refunds must restore each original payment portion only once. The resulting balance and refund records survive a backend restart.\n\n"},{"id":"ecommerce.spec.subscriptions.subscriptions","owners":["ecommerce.spec.subscriptions"],"requiresFeatures":["ecommerce.feature.subscriptions"],"text":"## Scheduled purchases\n\nPending deliveries and pauses survive a backend restart. Process elapsed pending slots after recovery. Completed delivery slots must not run again. Customers cannot change another account's subscription.\n"},{"id":"ecommerce.feature.product-bundles","owners":["ecommerce.feature.product-bundles"],"text":"## Product bundles\n\nCatalog staff can create and edit a named bundle of existing products, with a quantity\nfor each component and one bundle price. Show bundles and their components in the catalog.\nBundles contain products only, not other bundles.\n"},{"id":"ecommerce.feature.bundle-checkout","owners":["ecommerce.feature.bundle-checkout"],"text":"## Bundle checkout\n\nCustomers can add a whole bundle to their cart and buy it through checkout. Its components\nuse the existing stock reservations and reservation lifetime. Removing a bundle releases\nits reservation. Show the bundle as one order line at its bundle price.\n"},{"id":"ecommerce.feature.bundle-returns","owners":["ecommerce.feature.bundle-returns"],"text":"## Bundle returns\n\nCustomers can return a shipped bundle as a whole. Restore the purchased component quantities\nto their original warehouses and refund the price paid. Show the return and refund on the\norder. Partial bundle returns are not supported.\n"}]},"track":"ecommerce"},"execution":{"capabilities":["backend-lifecycle","browser","concurrent-actors","database-observation","database-read","direct-database-write","direct-server-call","process-crash","request-replay"],"execution":[{"checkGroups":[{"checkGroupId":"accounts","feature":{"actors":["shopper"],"criteria":[{"id":"1a","steps":[{"actor":"shopper","do":"signUp","name":"ann"},{"actor":"shopper","contains":"ann","do":"expect","testid":"current-user","within":6000}]}],"id":1,"setup":[]},"packId":"ecommerce.feature.accounts","role":"feature","source":"scenarios/01-account-create.json"}],"id":"selected-source-001","scenario":{"level":1,"writeUrlPattern":null},"source":"scenarios/01-account-create.json"},{"checkGroups":[{"checkGroupId":"accounts","feature":{"actors":["owner","impostor"],"criteria":[{"id":"1b","steps":[{"actor":"impostor","do":"signUp","expectFailure":true,"name":"ann","password":"different-pw"},{"actor":"impostor","do":"expect","testid":"auth-error","within":6000},{"absent":true,"actor":"impostor","do":"expect","testid":"current-user"}]}],"id":1,"setup":[{"actor":"owner","do":"signUp","name":"ann"}]},"packId":"ecommerce.feature.accounts","role":"feature","source":"scenarios/01-account-duplicate.json"}],"id":"selected-source-002","scenario":{"level":1,"writeUrlPattern":null},"source":"scenarios/01-account-duplicate.json"},{"checkGroups":[{"checkGroupId":"accounts","feature":{"actors":["owner","impostor"],"criteria":[{"id":"1c","steps":[{"actor":"impostor","do":"signIn","expectFailure":true,"name":"ann","password":"wrong-pw"},{"actor":"impostor","do":"expect","testid":"auth-error","within":6000},{"absent":true,"actor":"impostor","do":"expect","testid":"current-user"}]}],"id":1,"setup":[{"actor":"owner","do":"signUp","name":"ann"}]},"packId":"ecommerce.feature.accounts","role":"feature","source":"scenarios/01-account-password.json"}],"id":"selected-source-003","scenario":{"level":1,"writeUrlPattern":null},"source":"scenarios/01-account-password.json"},{"checkGroups":[{"checkGroupId":"session-reload","feature":{"actors":["shopper"],"criteria":[{"id":"1e","steps":[{"actor":"shopper","do":"reload","settleMs":4000},{"actor":"shopper","contains":"ann","do":"expect","testid":"current-user","within":6000}]}],"id":1,"setup":[{"actor":"shopper","do":"signUp","name":"ann"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.state-durability","requiresFeatures":["ecommerce.feature.accounts"],"role":"guarantee","source":"scenarios/01-account-reload.json"}],"id":"selected-source-004","scenario":{"level":1,"writeUrlPattern":null},"source":"scenarios/01-account-reload.json"},{"checkGroups":[{"checkGroupId":"accounts","feature":{"actors":["shopper"],"criteria":[{"id":"1d","steps":[{"actor":"shopper","do":"click","testid":"current-user","unlessVisible":"signout"},{"actor":"shopper","do":"click","testid":"signout"},{"actor":"shopper","do":"waitUntilAbsent","testid":"current-user","within":6000},{"actor":"shopper","do":"signIn","name":"ann"},{"actor":"shopper","contains":"ann","do":"expect","testid":"current-user","within":6000}]}],"id":1,"setup":[{"actor":"shopper","do":"signUp","name":"ann"}]},"packId":"ecommerce.feature.accounts","role":"feature","source":"scenarios/01-account-signout.json"}],"id":"selected-source-005","scenario":{"level":1,"writeUrlPattern":null},"source":"scenarios/01-account-signout.json"},{"checkGroups":[{"checkGroupId":"admin-write","feature":{"actors":["admin","staff"],"criteria":[{"id":"103a","steps":[{"actor":"staff","as":"purifier-before-control","do":"recordNumber","in":{"contains":"Air Purifier","testid":"item-card"},"testid":"item-stock"},{"action":"restock","actor":"admin","do":"callAction","input":{"attribute":"data-restock-input","contains":"Air Purifier","testid":"admin-location-row"},"namedAction":{"args":[0,0,1],"id":"restock","params":[{"in":"body","name":"itemId","wireType":"u64"},{"in":"body","name":"warehouseId","wireType":"u64"},{"in":"body","name":"quantity"}],"path":"/api/admin/restock","reducer":"admin_restock"},"settleMs":2000},{"actor":"admin","do":"expectActionOutcome","outcome":"accepted"},{"actor":"staff","do":"reload","settleMs":2000},{"actor":"staff","do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026","readyTestid":"current-user"},{"actor":"staff","do":"expectNumber","in":{"contains":"Air Purifier","testid":"item-card"},"plus":1,"relativeTo":"purifier-before-control","testid":"item-stock"}]}],"id":103,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"admin","do":"click","testid":"admin-link"}]},"packId":"ecommerce.feature.warehouse-admin","role":"feature","source":"scenarios/01-admin-write-staff.json"},{"checkGroupId":"warehouse-write-boundary","feature":{"actors":["admin","staff"],"criteria":[{"id":"103b","steps":[{"action":"restock","actor":"admin","do":"callAction","input":{"attribute":"data-restock-input","contains":"Air Purifier","testid":"admin-location-row"},"namedAction":{"args":[0,0,1],"id":"restock","params":[{"in":"body","name":"itemId","wireType":"u64"},{"in":"body","name":"warehouseId","wireType":"u64"},{"in":"body","name":"quantity"}],"path":"/api/admin/restock","reducer":"admin_restock"},"settleMs":2000},{"actor":"admin","do":"expectActionOutcome","outcome":"accepted"},{"actor":"staff","do":"reload","settleMs":2000},{"actor":"staff","do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026","readyTestid":"current-user"},{"actor":"staff","as":"purifier-before-refusal","do":"recordNumber","in":{"contains":"Air Purifier","testid":"item-card"},"testid":"item-stock"},{"action":"restock","actor":"staff","do":"callAction","from":"admin","input":{"attribute":"data-restock-input","contains":"Air Purifier","testid":"admin-location-row"},"namedAction":{"args":[0,0,1],"id":"restock","params":[{"in":"body","name":"itemId","wireType":"u64"},{"in":"body","name":"warehouseId","wireType":"u64"},{"in":"body","name":"quantity"}],"path":"/api/admin/restock","reducer":"admin_restock"},"settleMs":2000},{"actor":"staff","do":"expectActionOutcome","outcome":"refused","routeProvenBy":"admin"},{"actor":"staff","do":"reload","settleMs":2000},{"actor":"staff","do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026","readyTestid":"current-user"},{"actor":"staff","do":"expectNumber","in":{"contains":"Air Purifier","testid":"item-card"},"plus":0,"relativeTo":"purifier-before-refusal","testid":"item-stock"}]}],"id":103,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"admin","do":"click","testid":"admin-link"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","requiresFeatures":["ecommerce.feature.warehouse-admin"],"role":"guarantee","source":"scenarios/01-admin-write-staff.json"}],"id":"selected-source-006","scenario":{"level":1,"writeUrlPattern":null},"source":"scenarios/01-admin-write-staff.json"},{"checkGroups":[{"checkGroupId":"purchase-stock","feature":{"actors":["buyer","watcher","visitor"],"criteria":[{"id":"3b","steps":[{"actor":"watcher","do":"expectNumber","equals":100,"in":{"contains":"Espresso Machine","testid":"item-card"},"testid":"item-stock"},{"actor":"buyer","do":"click","in":{"contains":"Espresso Machine","testid":"item-card"},"testid":"buy-now"},{"actor":"watcher","do":"expectNumber","equals":99,"in":{"contains":"Espresso Machine","testid":"item-card"},"testid":"item-stock"},{"actor":"visitor","do":"expectNumber","equals":99,"in":{"contains":"Espresso Machine","testid":"item-card"},"testid":"item-stock"}]}],"id":3,"setup":[{"actor":"buyer","do":"signUp","name":"eli"},{"actor":"watcher","do":"signUp","name":"fay"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.live-state","requiresFeatures":["ecommerce.feature.catalog-items","ecommerce.feature.purchasing"],"role":"guarantee","source":"scenarios/01-buying.json"}],"id":"selected-source-007","scenario":{"level":1,"writeUrlPattern":null},"source":"scenarios/01-buying.json"},{"checkGroups":[{"checkGroupId":"cart-boundary","feature":{"actors":["owner","stranger"],"criteria":[{"id":"109a","steps":[{"action":"cart-add","actor":"stranger","do":"callAction","input":{"attribute":"data-buy-input","contains":"Coffee Grinder","testid":"item-card"},"namedAction":{"args":[0],"id":"cart-add","params":[{"in":"body","name":"itemId","wireType":"u64"}],"path":"/api/cart","reducer":"add_to_cart"},"settleMs":2000},{"actor":"stranger","do":"expectActionOutcome","outcome":"accepted"},{"actor":"owner","do":"reload","settleMs":1500},{"actor":"owner","do":"ensureSignedIn","name":"vic","readyTestid":"current-user"},{"actor":"owner","do":"click","ifAvailable":true,"testid":"overlay-close"},{"actor":"owner","do":"click","ifAvailable":true,"testid":"catalog-link"},{"actor":"owner","do":"click","testid":"cart-toggle","unlessVisible":"cart-total"},{"actor":"stranger","do":"reload","settleMs":1500},{"actor":"stranger","do":"ensureSignedIn","name":"wes","readyTestid":"current-user"},{"actor":"stranger","do":"click","ifAvailable":true,"testid":"overlay-close"},{"actor":"stranger","do":"click","ifAvailable":true,"testid":"catalog-link"},{"actor":"owner","contains":"Coffee Grinder","count":1,"do":"expect","testid":"cart-item"},{"actor":"owner","do":"expectNumber","equals":1,"in":{"contains":"Coffee Grinder","testid":"cart-item"},"testid":"cart-quantity"},{"actor":"stranger","do":"click","testid":"cart-toggle","unlessVisible":"cart-total"},{"actor":"stranger","contains":"Coffee Grinder","count":1,"do":"expect","testid":"cart-item"},{"actor":"stranger","do":"expectNumber","equals":1,"in":{"contains":"Coffee Grinder","testid":"cart-item"},"testid":"cart-quantity"}]},{"id":"109b","steps":[{"actor":"owner","as":"cart-total-before-invalid","do":"recordNumber","testid":"cart-total"},{"actor":"owner","as":"cart-quantity-before-invalid","do":"recordNumber","in":{"contains":"Coffee Grinder","testid":"cart-item"},"testid":"cart-quantity"},{"action":"cart-set-quantity","actor":"owner","do":"callAction","input":{"attribute":"data-cart-input","contains":"Coffee Grinder","testid":"cart-item"},"namedAction":{"args":[0,-3],"id":"cart-set-quantity","method":"PATCH","params":[{"in":"path","name":"itemId","placeholder":":itemId","wireType":"u64"},{"in":"body","name":"quantity"}],"path":"/api/cart/:itemId","reducer":"update_cart_quantity"},"settleMs":2000},{"actor":"owner","do":"expectActionOutcome","outcome":"validation-refused"},{"actor":"owner","do":"reload","settleMs":1500},{"actor":"owner","do":"ensureSignedIn","name":"vic","readyTestid":"current-user"},{"actor":"owner","do":"click","ifAvailable":true,"testid":"overlay-close"},{"actor":"owner","do":"click","ifAvailable":true,"testid":"catalog-link"},{"actor":"owner","do":"click","testid":"cart-toggle","unlessVisible":"cart-total"},{"actor":"owner","do":"expectNumber","plus":0,"relativeTo":"cart-total-before-invalid","testid":"cart-total"},{"actor":"owner","do":"expectNumber","in":{"contains":"Coffee Grinder","testid":"cart-item"},"plus":0,"relativeTo":"cart-quantity-before-invalid","testid":"cart-quantity"}]}],"id":109,"setup":[{"actor":"owner","do":"signUp","name":"vic"},{"actor":"stranger","do":"signUp","name":"wes"},{"actor":"owner","do":"click","in":{"contains":"Coffee Grinder","testid":"item-card"},"testid":"add-to-cart"},{"actor":"owner","do":"wait","ms":1500},{"actor":"owner","do":"click","testid":"cart-toggle","unlessVisible":"cart-total"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","requiresFeatures":["ecommerce.feature.cart"],"role":"guarantee","source":"scenarios/01-cart-boundary.json"}],"id":"selected-source-008","scenario":{"level":1,"writeUrlPattern":"\\/api\\/|\\/items|\\/cart|\\/orders|\\/checkout|\\/buy|\\/reviews|\\/stock|\\/restock|\\/warehouses"},"source":"scenarios/01-cart-boundary.json"},{"checkGroups":[{"checkGroupId":"cart-reload","feature":{"actors":["quantity","reload","live1","live2","checkout"],"criteria":[{"id":"4b","steps":[{"actor":"reload","do":"click","in":{"contains":"Laptop Stand","testid":"item-card"},"testid":"add-to-cart"},{"actor":"reload","do":"click","testid":"cart-toggle","unlessVisible":"cart-total"},{"actor":"reload","contains":"Laptop Stand","do":"expect","testid":"cart-item","within":10000},{"actor":"reload","do":"reload","settleMs":3000},{"actor":"reload","do":"ensureSignedIn","name":"omar","readyTestid":"current-user"},{"actor":"reload","do":"click","testid":"cart-toggle","unlessVisible":"cart-total"},{"actor":"reload","contains":"Laptop Stand","do":"expect","testid":"cart-item"}]}],"id":4,"setup":[{"actor":"quantity","do":"signUp","name":"nora"},{"actor":"reload","do":"signUp","name":"omar"},{"actor":"live1","do":"signUp","name":"pia"},{"actor":"checkout","do":"signUp","name":"quinn"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.state-durability","requiresFeatures":["ecommerce.feature.cart"],"role":"guarantee","source":"scenarios/01-cart.json"},{"checkGroupId":"shared-cart","feature":{"actors":["quantity","reload","live1","live2","checkout"],"criteria":[{"id":"4c","steps":[{"actor":"live2","do":"signIn","name":"pia"},{"actor":"live2","do":"click","testid":"cart-toggle","unlessVisible":"cart-total"},{"actor":"live1","do":"click","in":{"contains":"Induction Cooktop","testid":"item-card"},"testid":"add-to-cart"},{"actor":"live2","contains":"Induction Cooktop","do":"expect","testid":"cart-item","within":10000}]}],"id":4,"setup":[{"actor":"quantity","do":"signUp","name":"nora"},{"actor":"reload","do":"signUp","name":"omar"},{"actor":"live1","do":"signUp","name":"pia"},{"actor":"checkout","do":"signUp","name":"quinn"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.live-state","requiresFeatures":["ecommerce.feature.cart"],"role":"guarantee","source":"scenarios/01-cart.json"}],"id":"selected-source-009","scenario":{"level":1,"writeUrlPattern":null},"source":"scenarios/01-cart.json"},{"checkGroups":[{"checkGroupId":"catalog-ranking","feature":{"actors":["visitor"],"criteria":[{"id":"2b","steps":[{"actor":"visitor","do":"expectSequence","equals":["Air Purifier","Bluetooth Speaker","Coffee Grinder","Desk Lamp","Espresso Machine","Gaming Mouse","Headphones","Induction Cooktop","Keyboard","Laptop Stand"],"in":{"testid":"item-list"},"testid":"item-name"}]}],"id":2,"setup":[]},"packId":"ecommerce.feature.catalog-discovery","role":"feature","source":"scenarios/01-catalog-ranking.json","stablePackId":"ecommerce.feature.catalog"}],"id":"selected-source-010","scenario":{"level":1,"writeUrlPattern":null},"source":"scenarios/01-catalog-ranking.json"},{"checkGroups":[{"checkGroupId":"catalog-search","feature":{"actors":["visitor"],"criteria":[{"id":"2d","steps":[{"actor":"visitor","do":"fill","enter":true,"settleMs":1500,"testid":"search-input","text":"mirrorLESS"},{"actor":"visitor","contains":"Mirrorless Camera","do":"expect","in":{"testid":"search-results"},"testid":"item-card"}]}],"id":2,"setup":[]},"packId":"ecommerce.feature.catalog-discovery","role":"feature","source":"scenarios/01-catalog-search.json","stablePackId":"ecommerce.feature.catalog"}],"id":"selected-source-011","scenario":{"level":1,"writeUrlPattern":null},"source":"scenarios/01-catalog-search.json"},{"checkGroups":[{"checkGroupId":"catalog-values","feature":{"actors":["visitor"],"criteria":[{"id":"2a","steps":[{"actor":"visitor","contains":"Air Purifier","do":"expect","testid":"item-card"},{"actor":"visitor","do":"expectNumber","equals":189,"in":{"contains":"Air Purifier","testid":"item-card"},"testid":"item-price"},{"actor":"visitor","do":"expectNumber","equals":100,"in":{"contains":"Air Purifier","testid":"item-card"},"testid":"item-stock"}]}],"id":2,"setup":[]},"packId":"ecommerce.feature.catalog-items","role":"feature","source":"scenarios/01-catalog-values.json","stablePackId":"ecommerce.feature.catalog"}],"id":"selected-source-012","scenario":{"level":1,"writeUrlPattern":null},"source":"scenarios/01-catalog-values.json"},{"checkGroups":[{"checkGroupId":"ranking","feature":{"actors":["buyer","visitor","inspector"],"criteria":[{"id":"2c","steps":[{"actor":"buyer","do":"click","in":{"contains":"Coffee Grinder","testid":"item-card"},"testid":"buy-now"},{"actor":"visitor","do":"expectSequence","equals":["Coffee Grinder","Air Purifier","Bluetooth Speaker","Desk Lamp","Espresso Machine","Gaming Mouse","Headphones","Induction Cooktop","Keyboard","Laptop Stand"],"in":{"testid":"item-list"},"testid":"item-name","within":10000},{"actors":["buyer","visitor"],"do":"expectAgreement","in":{"contains":"Coffee Grinder","testid":"item-card"},"numeric":true,"testid":"item-stock"}]}],"id":2,"setup":[{"actor":"buyer","do":"signUp","name":"dov"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.live-state","requiresFeatures":["ecommerce.feature.catalog-items","ecommerce.feature.purchasing"],"role":"guarantee","source":"scenarios/01-core.json"}],"id":"selected-source-013","scenario":{"level":1,"writeUrlPattern":null},"source":"scenarios/01-core.json"},{"checkGroups":[{"checkGroupId":"duplicate-checkout","feature":{"actors":["tab1","tab2","filler"],"criteria":[{"id":"203a","steps":[{"actor":"tab1","contains":"Gaming Mouse","count":1,"do":"expect","testid":"cart-item"},{"actor":"tab1","do":"expectNumber","equals":2,"in":{"contains":"Gaming Mouse","testid":"cart-item"},"testid":"cart-quantity"}]},{"id":"203b","steps":[{"actor":"tab1","do":"click","testid":"checkout-submit"},{"actor":"tab1","do":"wait","ms":2500},{"actor":"filler","as":"keyboard-before-checkout","do":"recordNumber","in":{"contains":"Keyboard","testid":"item-card"},"testid":"item-stock"},{"account":"{user:twin}","as":"checkout-before","do":"dbRecordCheckout","item":"Keyboard","storage":{"cart":true,"kind":"order-data","warehouses":false}},{"actor":"filler","do":"click","in":{"contains":"Keyboard","testid":"item-card"},"testid":"add-to-cart"},{"actor":"filler","do":"wait","ms":2000},{"account":"{user:twin}","as":"checkout-prepared","do":"dbRecordCheckout","item":"Keyboard","storage":{"cart":true,"kind":"order-data","warehouses":false}},{"action":"checkout","actors":["tab1","tab2"],"do":"callConcurrently","settleMs":5000},{"do":"expectCallOutcomes"},{"before":"checkout-before","do":"dbExpectCheckout","prepared":"checkout-prepared","quantity":1},{"actor":"filler","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"filler","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"filler","contains":"Keyboard","count":1,"do":"expect","testid":"order-item"},{"actor":"filler","do":"reload","settleMs":2000},{"actor":"filler","do":"ensureSignedIn","name":"twin","readyTestid":"current-user"},{"actor":"filler","do":"click","ifAvailable":true,"testid":"overlay-close"},{"actor":"filler","do":"click","ifAvailable":true,"testid":"catalog-link"},{"actor":"filler","do":"expectNumber","in":{"contains":"Keyboard","testid":"item-card"},"plus":-1,"relativeTo":"keyboard-before-checkout","testid":"item-stock"}]}],"id":203,"setup":[{"actor":"tab1","do":"signUp","name":"twin"},{"actor":"tab2","do":"signIn","name":"twin"},{"actor":"filler","do":"signIn","name":"twin"},{"actors":["tab1","tab2"],"do":"clickConcurrently","in":{"contains":"Gaming Mouse","testid":"item-card"},"settleMs":4000,"testid":"add-to-cart"},{"actor":"tab1","do":"reload","settleMs":2500},{"actor":"tab1","do":"ensureSignedIn","name":"twin","readyTestid":"current-user"},{"actor":"tab1","do":"click","testid":"cart-toggle","unlessVisible":"cart-total"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.concurrency-safety","requiresFeatures":["ecommerce.feature.checkout"],"role":"guarantee","source":"scenarios/01-duplicate-checkout.json"}],"id":"selected-source-014","scenario":{"level":1,"writeUrlPattern":"\\/api\\/|\\/items|\\/cart|\\/orders|\\/checkout|\\/buy|\\/reviews|\\/stock|\\/restock|\\/warehouses"},"source":"scenarios/01-duplicate-checkout.json"},{"checkGroups":[{"checkGroupId":"external-stock","feature":{"actors":["viewer"],"criteria":[{"id":"901a","steps":[{"do":"dbSetStock","item":"Desk Lamp","quantity":5,"settleMs":4000,"warehouse":"East"},{"actor":"viewer","do":"expectNumber","equals":50,"in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"item-stock","within":10000}]}],"id":901,"setup":[{"actor":"viewer","do":"expectNumber","equals":100,"in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"item-stock","within":10000}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.external-data-sync","requiresFeatures":["ecommerce.feature.warehouse-admin"],"role":"guarantee","source":"scenarios/01-external-live-sync.json"}],"id":"selected-source-015","scenario":{"level":1,"writeUrlPattern":"\\/api\\/|\\/items|\\/stock|\\/warehouses"},"source":"scenarios/01-external-live-sync.json"},{"checkGroups":[{"checkGroupId":"external-stock","feature":{"actors":["viewer"],"criteria":[{"id":"901d","steps":[{"actor":"viewer","do":"setOffline","offline":true,"settleMs":1000},{"do":"dbSetStock","item":"Desk Lamp","quantity":7,"settleMs":4000,"warehouse":"East"},{"actor":"viewer","do":"setOffline","offline":false,"settleMs":1000},{"actor":"viewer","do":"expectNumber","equals":52,"in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"item-stock","within":20000}]}],"id":901,"setup":[{"actor":"viewer","do":"expectNumber","equals":100,"in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"item-stock","within":10000}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.external-data-sync","requiresFeatures":["ecommerce.feature.warehouse-admin"],"role":"guarantee","source":"scenarios/01-external-reconnect-sync.json"}],"id":"selected-source-016","scenario":{"level":1,"writeUrlPattern":"\\/api\\/|\\/items|\\/stock|\\/warehouses"},"source":"scenarios/01-external-reconnect-sync.json"},{"checkGroups":[{"checkGroupId":"external-stock","feature":{"actors":["viewer"],"criteria":[{"id":"901b","steps":[{"do":"dbSetStock","item":"Desk Lamp","quantity":5,"settleMs":1000,"warehouse":"East"},{"actor":"viewer","do":"reload","settleMs":3000},{"actor":"viewer","do":"expectNumber","equals":50,"in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"item-stock","within":10000}]}],"id":901,"setup":[{"actor":"viewer","do":"expectNumber","equals":100,"in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"item-stock","within":10000}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.external-data-sync","requiresFeatures":["ecommerce.feature.warehouse-admin"],"role":"guarantee","source":"scenarios/01-external-reload-sync.json"}],"id":"selected-source-017","scenario":{"level":1,"writeUrlPattern":"\\/api\\/|\\/items|\\/stock|\\/warehouses"},"source":"scenarios/01-external-reload-sync.json"},{"checkGroups":[{"checkGroupId":"external-stock","feature":{"actors":["viewer"],"criteria":[{"id":"901c","steps":[{"do":"stopAppServer"},{"do":"dbSetStock","item":"Desk Lamp","quantity":10,"settleMs":4000,"warehouse":"West"},{"do":"startAppServer"},{"actor":"viewer","do":"expectNumber","equals":65,"in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"item-stock","within":20000}]}],"id":901,"setup":[{"actor":"viewer","do":"expectNumber","equals":100,"in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"item-stock","within":10000}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.external-data-sync","requiresFeatures":["ecommerce.feature.warehouse-admin"],"role":"guarantee","source":"scenarios/01-external-server-restart-sync.json"}],"id":"selected-source-018","scenario":{"level":1,"writeUrlPattern":"\\/api\\/|\\/items|\\/stock|\\/warehouses"},"source":"scenarios/01-external-server-restart-sync.json"},{"checkGroups":[{"checkGroupId":"last-unit","feature":{"actors":["admin","a","b","c","d","e","f"],"criteria":[{"id":"201a","steps":[{"do":"dbExpectStock","equals":0,"item":"Air Purifier","warehouse":"East"},{"do":"dbExpectStock","equals":0,"item":"Air Purifier","warehouse":"West"},{"actor":"a","do":"expectNumber","equals":0,"in":{"contains":"Air Purifier","testid":"item-card"},"testid":"item-stock"},{"actors":["a","b","c","d","e","f"],"do":"expectAgreement","in":{"contains":"Air Purifier","testid":"item-card"},"numeric":true,"testid":"item-stock"}]},{"id":"201c","steps":[{"actor":"admin","do":"reload","settleMs":1000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"admin","do":"click","testid":"admin-link","unlessVisible":"admin-revenue"},{"actor":"admin","do":"expectNumber","plus":567,"relativeTo":"revenue-before-last-unit","testid":"admin-revenue","within":10000}]},{"id":"201b","steps":[{"before":{"a":"buy-a","b":"buy-b","c":"buy-c","d":"buy-d","e":"buy-e","f":"buy-f"},"do":"dbExpectPurchases","purchases":3},{"actor":"a","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"a","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"b","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"b","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"c","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"c","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"d","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"d","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"e","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"e","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"f","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"f","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actors":["a","b","c","d","e","f"],"contains":"Air Purifier","do":"expectActorsWith","equals":3,"maxEach":1,"testid":"order-item"},{"do":"dbSetStock","item":"Air Purifier","quantity":2,"settleMs":250,"warehouse":"East"},{"do":"dbSetStock","item":"Air Purifier","quantity":2,"settleMs":250,"warehouse":"West"},{"actor":"a","do":"reload","settleMs":1000},{"actor":"a","do":"ensureSignedIn","name":"c1","readyTestid":"current-user"},{"actor":"a","do":"click","ifAvailable":true,"testid":"catalog-link"},{"account":"{user:c1}","as":"ample-a","do":"dbRecordCheckout","item":"Air Purifier","storage":{"cart":false,"kind":"order-data","warehouses":true}},{"account":"{user:c2}","as":"ample-b","do":"dbRecordCheckout","item":"Air Purifier","storage":{"cart":false,"kind":"order-data","warehouses":true}},{"action":"buy","actors":["a","b"],"do":"callConcurrently","from":"a","input":{"attribute":"data-buy-input","contains":"Air Purifier","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"},"requests":4,"settleMs":3000},{"do":"expectCallOutcomes"},{"before":{"a":"ample-a","b":"ample-b"},"do":"dbExpectPurchases","purchases":4}]}],"id":201,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"click","testid":"admin-link"},{"actor":"admin","as":"revenue-before-last-unit","do":"recordNumber","testid":"admin-revenue"},{"do":"dbSetStock","item":"Air Purifier","quantity":2,"settleMs":250,"warehouse":"East"},{"do":"dbSetStock","item":"Air Purifier","quantity":1,"settleMs":250,"warehouse":"West"},{"actor":"a","do":"signUp","name":"c1"},{"actor":"b","do":"signUp","name":"c2"},{"actor":"c","do":"signUp","name":"c3"},{"actor":"d","do":"signUp","name":"c4"},{"actor":"e","do":"signUp","name":"c5"},{"actor":"f","do":"signUp","name":"c6"},{"account":"{user:c1}","as":"buy-a","do":"dbRecordCheckout","item":"Air Purifier","storage":{"cart":false,"kind":"order-data","warehouses":true}},{"account":"{user:c2}","as":"buy-b","do":"dbRecordCheckout","item":"Air Purifier","storage":{"cart":false,"kind":"order-data","warehouses":true}},{"account":"{user:c3}","as":"buy-c","do":"dbRecordCheckout","item":"Air Purifier","storage":{"cart":false,"kind":"order-data","warehouses":true}},{"account":"{user:c4}","as":"buy-d","do":"dbRecordCheckout","item":"Air Purifier","storage":{"cart":false,"kind":"order-data","warehouses":true}},{"account":"{user:c5}","as":"buy-e","do":"dbRecordCheckout","item":"Air Purifier","storage":{"cart":false,"kind":"order-data","warehouses":true}},{"account":"{user:c6}","as":"buy-f","do":"dbRecordCheckout","item":"Air Purifier","storage":{"cart":false,"kind":"order-data","warehouses":true}},{"action":"buy","actors":["a","b","c","d","e","f"],"do":"callConcurrently","input":{"attribute":"data-buy-input","contains":"Air Purifier","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"},"settleMs":6000},{"do":"expectCallOutcomes"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.concurrency-safety","requiresFeatures":["ecommerce.feature.catalog-items","ecommerce.feature.purchasing","ecommerce.feature.warehouse-admin"],"role":"guarantee","source":"scenarios/01-last-unit.json"}],"id":"selected-source-019","scenario":{"level":1,"writeUrlPattern":"\\/api\\/|\\/items|\\/cart|\\/orders|\\/checkout|\\/buy|\\/reviews|\\/stock|\\/restock|\\/warehouses"},"source":"scenarios/01-last-unit.json"},{"checkGroups":[{"checkGroupId":"order-ownership","feature":{"actors":["one","two"],"criteria":[{"id":"106a","steps":[{"actor":"one","do":"click","in":{"contains":"Coffee Grinder","testid":"item-card"},"testid":"buy-now"},{"actor":"two","do":"click","in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"buy-now"},{"actor":"two","do":"wait","ms":2000},{"actor":"two","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"two","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"two","contains":"Desk Lamp","count":1,"do":"expect","testid":"order-item"},{"absent":true,"actor":"two","contains":"Coffee Grinder","do":"expect","testid":"order-item"}]}],"id":106,"setup":[{"actor":"one","do":"signUp","name":"quin"},{"actor":"two","do":"signUp","name":"ros"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","requiresFeatures":["ecommerce.feature.purchasing"],"role":"guarantee","source":"scenarios/01-order-ownership.json"}],"id":"selected-source-020","scenario":{"level":1,"writeUrlPattern":"\\/api\\/|\\/items|\\/cart|\\/orders|\\/checkout|\\/buy|\\/reviews|\\/stock|\\/restock|\\/warehouses"},"source":"scenarios/01-order-ownership.json"},{"checkGroups":[{"checkGroupId":"purchase-attribution","feature":{"actors":["victim","attacker"],"criteria":[{"id":"102a","steps":[{"action":"buy","actor":"attacker","do":"callAction","input":{"attribute":"data-buy-input","contains":"Desk Lamp","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"},"settleMs":2000},{"actor":"attacker","do":"expectActionOutcome","outcome":"accepted"},{"actor":"victim","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"victim","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"victim","contains":"Coffee Grinder","count":1,"do":"expect","testid":"order-item"},{"absent":true,"actor":"victim","contains":"Desk Lamp","do":"expect","testid":"order-item"},{"actor":"attacker","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"attacker","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"attacker","contains":"Desk Lamp","count":1,"do":"expect","testid":"order-item"}]}],"id":102,"setup":[{"actor":"victim","do":"signUp","name":"lee"},{"actor":"attacker","do":"signUp","name":"mel"},{"actor":"victim","do":"click","in":{"contains":"Coffee Grinder","testid":"item-card"},"testid":"buy-now"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","requiresFeatures":["ecommerce.feature.purchasing"],"role":"guarantee","source":"scenarios/01-purchase-attribution.json"}],"id":"selected-source-021","scenario":{"level":1,"writeUrlPattern":null},"source":"scenarios/01-purchase-attribution.json"},{"checkGroups":[{"checkGroupId":"purchase-session","feature":{"actors":["buyer","guest"],"criteria":[{"id":"101a","steps":[{"action":"buy","actor":"guest","authentication":"none","do":"callAction","from":"buyer","input":{"attribute":"data-buy-input","contains":"Bluetooth Speaker","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"},"settleMs":2000},{"actor":"guest","do":"expectActionOutcome","outcome":"refused","routeProvenBy":"buyer"},{"do":"dbExpectStock","item":"Bluetooth Speaker","plus":-1,"relativeTo":"speaker-before-control"}]}],"id":101,"setup":[{"actor":"buyer","do":"signUp","name":"kim"},{"as":"speaker-before-control","do":"dbRecordStock","item":"Bluetooth Speaker"},{"action":"buy","actor":"buyer","do":"callAction","input":{"attribute":"data-buy-input","contains":"Bluetooth Speaker","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"},"settleMs":2000},{"actor":"buyer","do":"expectActionOutcome","outcome":"accepted"},{"do":"dbExpectStock","item":"Bluetooth Speaker","plus":-1,"relativeTo":"speaker-before-control"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","requiresFeatures":["ecommerce.feature.purchasing"],"role":"guarantee","source":"scenarios/01-purchase-session.json"}],"id":"selected-source-022","scenario":{"level":1,"writeUrlPattern":null},"source":"scenarios/01-purchase-session.json"},{"checkGroups":[{"checkGroupId":"restock-race","feature":{"actors":["admin","a","b","c"],"criteria":[{"id":"202-control","steps":[{"do":"dbExpectStock","item":"Bluetooth Speaker","plus":5,"relativeTo":"stored-before-control"},{"actor":"a","do":"expectNumber","in":{"contains":"Bluetooth Speaker","testid":"item-card"},"plus":5,"relativeTo":"storefront-before","testid":"item-stock","within":8000}]},{"id":"202a","steps":[{"as":"stored-before-rush","do":"dbRecordStock","item":"Bluetooth Speaker"},{"actor":"admin","do":"fill","in":{"contains":"Bluetooth Speaker","testid":"admin-location-row"},"testid":"restock-input","text":"5"},{"actor":"a","as":"rush-before","do":"recordNumber","in":{"contains":"Bluetooth Speaker","testid":"item-card"},"testid":"item-stock"},{"branches":[[{"actors":["a","b","c"],"do":"clickConcurrently","in":{"contains":"Bluetooth Speaker","testid":"item-card"},"settleMs":500,"testid":"buy-now"}],[{"actor":"admin","do":"click","in":{"contains":"Bluetooth Speaker","testid":"admin-location-row"},"testid":"restock-submit"}]],"do":"race","settleMs":6000},{"do":"dbExpectStock","item":"Bluetooth Speaker","plus":2,"relativeTo":"stored-before-rush"},{"atLeast":0,"do":"dbExpectStock","item":"Bluetooth Speaker","warehouse":"East"},{"atLeast":0,"do":"dbExpectStock","item":"Bluetooth Speaker","warehouse":"West"},{"actor":"a","do":"reload","settleMs":1000},{"actor":"a","do":"click","testid":"catalog-link"},{"actor":"a","do":"expectNumber","in":{"contains":"Bluetooth Speaker","testid":"item-card"},"plus":2,"relativeTo":"rush-before","testid":"item-stock","within":10000},{"actor":"a","do":"ensureSignedIn","name":"r1","readyTestid":"current-user"},{"actor":"a","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"a","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"a","contains":"Bluetooth Speaker","count":2,"do":"expect","testid":"order-item","within":10000},{"actor":"b","do":"reload","settleMs":1000},{"actor":"b","do":"ensureSignedIn","name":"r2","readyTestid":"current-user"},{"actor":"b","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"b","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"b","contains":"Bluetooth Speaker","count":1,"do":"expect","testid":"order-item","within":10000},{"actor":"c","do":"reload","settleMs":1000},{"actor":"c","do":"ensureSignedIn","name":"r3","readyTestid":"current-user"},{"actor":"c","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"c","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"c","contains":"Bluetooth Speaker","count":1,"do":"expect","testid":"order-item","within":10000},{"actor":"admin","do":"reload","settleMs":1000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"admin-link"},{"actor":"admin","do":"expectNumber","in":{"contains":"Bluetooth Speaker","testid":"admin-item-row"},"plus":2,"relativeTo":"stored-before-rush","testid":"admin-stock","within":10000},{"actor":"a","do":"reload","settleMs":1000},{"actor":"a","do":"click","testid":"catalog-link"},{"actor":"a","do":"expectNumber","in":{"contains":"Bluetooth Speaker","testid":"item-card"},"plus":2,"relativeTo":"stored-before-rush","testid":"item-stock","within":10000},{"actor":"a","do":"ensureSignedIn","name":"r1","readyTestid":"current-user"},{"account":"{user:r1}","as":"mixed-a","do":"dbRecordCheckout","item":"Bluetooth Speaker","storage":{"cart":false,"kind":"order-data","warehouses":true}},{"account":"{user:r2}","as":"mixed-b","do":"dbRecordCheckout","item":"Bluetooth Speaker","storage":{"cart":false,"kind":"order-data","warehouses":true}},{"account":"{user:r3}","as":"mixed-c","do":"dbRecordCheckout","item":"Bluetooth Speaker","storage":{"cart":false,"kind":"order-data","warehouses":true}},{"action":"buy","actors":["a","b","c"],"alongside":[{"action":"restock","actors":["admin"],"input":{"attribute":"data-restock-input","contains":"Bluetooth Speaker","testid":"admin-location-row"},"namedAction":{"args":[0,0,1],"id":"restock","params":[{"in":"body","name":"itemId","wireType":"u64"},{"in":"body","name":"warehouseId","wireType":"u64"},{"in":"body","name":"quantity"}],"path":"/api/admin/restock","reducer":"admin_restock"},"requests":1}],"do":"callConcurrently","from":"a","input":{"attribute":"data-buy-input","contains":"Bluetooth Speaker","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"},"requests":3,"settleMs":3000},{"accepted":4,"do":"expectCallOutcomes"},{"before":{"a":"mixed-a","b":"mixed-b","c":"mixed-c"},"do":"dbExpectPurchases","purchases":3}]}],"id":202,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"click","testid":"admin-link"},{"actor":"a","do":"signUp","name":"r1"},{"actor":"b","do":"signUp","name":"r2"},{"actor":"c","do":"signUp","name":"r3"},{"as":"stored-before-serial-purchase","do":"dbRecordStock","item":"Bluetooth Speaker"},{"actor":"a","do":"click","in":{"contains":"Bluetooth Speaker","testid":"item-card"},"testid":"buy-now"},{"actor":"a","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"a","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"a","contains":"Bluetooth Speaker","count":1,"do":"expect","testid":"order-item","within":10000},{"do":"dbExpectStock","item":"Bluetooth Speaker","plus":-1,"relativeTo":"stored-before-serial-purchase"},{"actor":"a","do":"reload","settleMs":1000},{"actor":"a","do":"ensureSignedIn","name":"r1","readyTestid":"current-user"},{"actor":"admin","do":"reload","settleMs":1000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","testid":"admin-link"},{"actor":"admin","do":"expectNumber","in":{"contains":"Bluetooth Speaker","testid":"admin-item-row"},"plus":-1,"relativeTo":"stored-before-serial-purchase","testid":"admin-stock","within":10000},{"as":"stored-before-control","do":"dbRecordStock","item":"Bluetooth Speaker"},{"actor":"admin","as":"warehouse-before","do":"recordNumber","in":{"contains":"Bluetooth Speaker","testid":"admin-location-row"},"testid":"admin-location-qty"},{"actor":"a","do":"click","testid":"catalog-link"},{"actor":"a","as":"storefront-before","do":"recordNumber","in":{"contains":"Bluetooth Speaker","testid":"item-card"},"testid":"item-stock"},{"actor":"admin","do":"fill","in":{"contains":"Bluetooth Speaker","testid":"admin-location-row"},"testid":"restock-input","text":"5"},{"actor":"admin","do":"click","in":{"contains":"Bluetooth Speaker","testid":"admin-location-row"},"testid":"restock-submit"},{"do":"dbExpectStock","item":"Bluetooth Speaker","plus":5,"relativeTo":"stored-before-control","within":8000},{"actor":"admin","do":"reload","settleMs":1000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","testid":"admin-link"},{"actor":"admin","do":"expectNumber","in":{"contains":"Bluetooth Speaker","testid":"admin-location-row"},"plus":5,"relativeTo":"warehouse-before","testid":"admin-location-qty","within":8000},{"actor":"a","do":"reload","settleMs":1000},{"actor":"a","do":"click","testid":"catalog-link"},{"actor":"a","do":"expectNumber","in":{"contains":"Bluetooth Speaker","testid":"item-card"},"plus":5,"relativeTo":"storefront-before","testid":"item-stock","within":8000},{"do":"dbExpectStock","item":"Bluetooth Speaker","plus":5,"relativeTo":"stored-before-control"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.concurrency-safety","requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.warehouse-admin"],"role":"guarantee","source":"scenarios/01-restock-race.json"}],"id":"selected-source-023","scenario":{"level":1,"writeUrlPattern":"\\/api\\/|\\/items|\\/cart|\\/orders|\\/checkout|\\/buy|\\/reviews|\\/stock|\\/restock|\\/warehouses"},"source":"scenarios/01-restock-race.json"},{"checkGroups":[{"checkGroupId":"review-eligibility","feature":{"actors":["owner","stranger"],"criteria":[{"id":"108a","steps":[{"action":"buy","actor":"owner","do":"callAction","input":{"attribute":"data-buy-input","contains":"Air Purifier","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"}},{"actor":"owner","do":"expectActionOutcome","outcome":"accepted"},{"actor":"owner","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"owner","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"owner","contains":"Air Purifier","do":"expect","testid":"order-item"},{"actor":"owner","do":"click","ifAvailable":true,"testid":"overlay-close"},{"actor":"owner","do":"click","ifAvailable":true,"testid":"catalog-link"},{"action":"submitReview","actor":"owner","do":"callAction","from":"owner","input":{"attribute":"data-buy-input","contains":"Air Purifier","testid":"item-card"},"namedAction":{"args":[0,4,"eligible review control"],"id":"submitReview","method":"POST","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"},{"in":"body","name":"rating"},{"in":"body","name":"comment"}],"path":"/api/items/:id/reviews","reducer":"submit_review"},"settleMs":1500},{"actor":"owner","do":"expectActionOutcome","outcome":"accepted"},{"actor":"stranger","do":"openItem","item":"Air Purifier"},{"actor":"stranger","contains":"eligible review control","do":"expect","testid":"review-item"},{"action":"submitReview","actor":"stranger","do":"callAction","from":"owner","input":{"attribute":"data-buy-input","contains":"Air Purifier","testid":"item-card"},"namedAction":{"args":[0,4,"never bought this"],"id":"submitReview","method":"POST","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"},{"in":"body","name":"rating"},{"in":"body","name":"comment"}],"path":"/api/items/:id/reviews","reducer":"submit_review"},"settleMs":1500},{"actor":"stranger","do":"expectActionOutcome","outcome":"application-refused","routeProvenBy":"owner"},{"actor":"stranger","do":"reload","settleMs":1500},{"actor":"stranger","do":"ensureSignedIn","name":"uma","readyTestid":"current-user"},{"actor":"stranger","do":"click","ifAvailable":true,"testid":"overlay-close"},{"actor":"stranger","do":"click","ifAvailable":true,"testid":"catalog-link"},{"actor":"stranger","do":"openItem","item":"Air Purifier"},{"actor":"stranger","contains":"eligible review control","do":"expect","testid":"review-item"},{"absent":true,"actor":"stranger","contains":"never bought this","do":"expect","testid":"review-item"}]},{"id":"108b","steps":[{"action":"buy","actor":"owner","do":"callAction","input":{"attribute":"data-buy-input","contains":"Keyboard","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"}},{"actor":"owner","do":"expectActionOutcome","outcome":"accepted"},{"actor":"owner","do":"openItem","item":"Keyboard"},{"actor":"owner","do":"click","ifAvailable":true,"testid":"review-toggle","unlessVisible":"review-rating"},{"actor":"owner","do":"fill","testid":"review-rating","text":"4"},{"actor":"owner","do":"fill","testid":"review-input","text":"bought and used it"},{"actor":"owner","do":"click","testid":"review-submit"},{"actor":"owner","contains":"bought and used it","do":"expect","testid":"review-item","within":8000}]}],"id":108,"setup":[{"actor":"owner","do":"signUp","name":"tam"},{"actor":"stranger","do":"signUp","name":"uma"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.reviews"],"role":"guarantee","source":"scenarios/01-review-eligibility.json"}],"id":"selected-source-024","scenario":{"level":1,"writeUrlPattern":"\\/api\\/|\\/items|\\/cart|\\/orders|\\/checkout|\\/buy|\\/reviews|\\/stock|\\/restock|\\/warehouses"},"source":"scenarios/01-review-eligibility.json"},{"checkGroups":[{"checkGroupId":"rating","feature":{"actors":["author","other"],"criteria":[{"id":"6c","steps":[{"actor":"other","do":"openItem","item":"Gaming Mouse"},{"actor":"other","do":"click","ifAvailable":true,"testid":"review-toggle","unlessVisible":"review-rating"},{"actor":"other","do":"fill","testid":"review-rating","text":"4"},{"actor":"other","do":"fill","testid":"review-input","text":"does the job"},{"actor":"other","do":"click","testid":"review-submit"},{"actor":"other","do":"expectNumber","equals":3,"testid":"review-average","within":10000},{"actors":["author","other"],"do":"expectAgreement","numeric":true,"testid":"review-average","within":10000}]}],"id":6,"setup":[{"actor":"author","do":"signUp","name":"leon"},{"actor":"other","do":"signUp","name":"maya"},{"action":"buy","actor":"author","do":"callAction","input":{"attribute":"data-buy-input","contains":"Gaming Mouse","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"}},{"actor":"author","do":"expectActionOutcome","outcome":"accepted"},{"actor":"author","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"author","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"author","contains":"Gaming Mouse","do":"expect","testid":"order-item","within":10000},{"actor":"author","do":"click","ifAvailable":true,"testid":"overlay-close"},{"actor":"author","do":"click","ifAvailable":true,"testid":"catalog-link"},{"actor":"author","do":"openItem","item":"Gaming Mouse"},{"actor":"author","do":"click","ifAvailable":true,"testid":"review-toggle","unlessVisible":"review-rating"},{"actor":"author","do":"fill","testid":"review-rating","text":"2"},{"actor":"author","do":"fill","testid":"review-input","text":"works for travel"},{"actor":"author","do":"click","testid":"review-submit"},{"actor":"author","contains":"works for travel","do":"expect","testid":"review-item"},{"action":"buy","actor":"other","do":"callAction","input":{"attribute":"data-buy-input","contains":"Gaming Mouse","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"}},{"actor":"other","do":"expectActionOutcome","outcome":"accepted"},{"actor":"other","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"other","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"other","contains":"Gaming Mouse","do":"expect","testid":"order-item","within":10000},{"actor":"other","do":"click","ifAvailable":true,"testid":"overlay-close"},{"actor":"other","do":"click","ifAvailable":true,"testid":"catalog-link"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.live-state","requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.reviews"],"role":"guarantee","source":"scenarios/01-review-rating-live.json"}],"id":"selected-source-025","scenario":{"level":1,"writeUrlPattern":null},"source":"scenarios/01-review-rating-live.json"},{"checkGroups":[{"checkGroupId":"unique-review","feature":{"actors":["author"],"criteria":[{"id":"6b","steps":[{"actor":"author","do":"click","ifAvailable":true,"testid":"overlay-close"},{"actor":"author","do":"click","ifAvailable":true,"testid":"catalog-link"},{"action":"submitReview","actor":"author","do":"callAction","from":"author","input":{"attribute":"data-buy-input","contains":"Air Purifier","testid":"item-card"},"namedAction":{"args":[0,4,"changed my mind"],"id":"submitReview","method":"POST","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"},{"in":"body","name":"rating"},{"in":"body","name":"comment"}],"path":"/api/items/:id/reviews","reducer":"submit_review"},"settleMs":1500},{"actor":"author","do":"expectActionOutcome","outcome":"completed"},{"actor":"author","do":"reload","settleMs":2500},{"actor":"author","do":"ensureSignedIn","name":"kira","readyTestid":"current-user"},{"actor":"author","do":"click","ifAvailable":true,"testid":"overlay-close"},{"actor":"author","do":"click","ifAvailable":true,"testid":"catalog-link"},{"actor":"author","do":"openItem","item":"Air Purifier"},{"actor":"author","count":1,"do":"expect","testid":"review-item","within":10000}]}],"id":6,"setup":[{"actor":"author","do":"signUp","name":"kira"},{"action":"buy","actor":"author","do":"callAction","input":{"attribute":"data-buy-input","contains":"Air Purifier","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"}},{"actor":"author","do":"expectActionOutcome","outcome":"accepted"},{"actor":"author","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"author","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"author","contains":"Air Purifier","do":"expect","testid":"order-item","within":10000},{"actor":"author","do":"click","ifAvailable":true,"testid":"overlay-close"},{"actor":"author","do":"click","ifAvailable":true,"testid":"catalog-link"},{"actor":"author","do":"openItem","item":"Air Purifier"},{"actor":"author","do":"click","ifAvailable":true,"testid":"review-toggle","unlessVisible":"review-rating"},{"actor":"author","do":"fill","testid":"review-rating","text":"4"},{"actor":"author","do":"fill","testid":"review-input","text":"quiet and effective"},{"actor":"author","do":"click","testid":"review-submit"},{"actor":"author","contains":"quiet and effective","do":"expect","testid":"review-item"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.transactional-integrity","requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.reviews"],"role":"guarantee","source":"scenarios/01-review-uniqueness.json"}],"id":"selected-source-026","scenario":{"level":1,"writeUrlPattern":null},"source":"scenarios/01-review-uniqueness.json"},{"checkGroups":[{"checkGroupId":"reviews","feature":{"actors":["author","visitor"],"criteria":[{"id":"6a","steps":[{"actor":"author","do":"openItem","item":"Induction Cooktop"},{"actor":"author","do":"click","ifAvailable":true,"testid":"review-toggle","unlessVisible":"review-rating"},{"actor":"author","do":"fill","testid":"review-rating","text":"4"},{"actor":"author","do":"fill","testid":"review-input","text":"solid mold"},{"actor":"author","do":"click","testid":"review-submit"},{"actor":"author","contains":"solid mold","do":"expect","testid":"review-item"},{"actor":"visitor","do":"openItem","item":"Induction Cooktop"},{"actor":"visitor","contains":"solid mold","do":"expect","testid":"review-item","within":10000}]}],"id":6,"setup":[{"actor":"author","do":"signUp","name":"hal"},{"actor":"author","do":"click","in":{"contains":"Induction Cooktop","testid":"item-card"},"testid":"buy-now"},{"actor":"author","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"author","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"author","contains":"Induction Cooktop","do":"expect","testid":"order-item","within":10000},{"actor":"author","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"author","do":"click","ifAvailable":true,"testid":"catalog-link"}]},"packId":"ecommerce.feature.reviews","role":"feature","source":"scenarios/01-review-visibility.json"}],"id":"selected-source-027","scenario":{"level":1,"writeUrlPattern":null},"source":"scenarios/01-review-visibility.json"},{"checkGroups":[{"checkGroupId":"server-price","feature":{"actors":["buyer"],"criteria":[{"id":"104a","steps":[{"action":"buy","actor":"buyer","do":"callAction","input":{"attribute":"data-buy-input","contains":"Espresso Machine","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"},"settleMs":2000},{"actor":"buyer","do":"expectActionOutcome","outcome":"accepted"},{"action":"buy","actor":"buyer","do":"callAction","input":{"attribute":"data-buy-input","contains":"Coffee Grinder","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"},"settleMs":2000},{"actor":"buyer","do":"expectActionOutcome","outcome":"accepted"},{"actor":"buyer","do":"freshClient"},{"actor":"buyer-fresh","do":"signIn","name":"oli"},{"actor":"buyer-fresh","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"buyer-fresh","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"buyer-fresh","count":2,"do":"expect","testid":"order-item"},{"actor":"buyer-fresh","contains":"Espresso Machine","count":1,"do":"expect","testid":"order-item"},{"actor":"buyer-fresh","do":"expectNumber","equals":449,"in":{"contains":"Espresso Machine","testid":"order-item"},"testid":"order-total"},{"actor":"buyer-fresh","contains":"Coffee Grinder","count":1,"do":"expect","testid":"order-item"},{"actor":"buyer-fresh","do":"expectNumber","equals":64,"in":{"contains":"Coffee Grinder","testid":"order-item"},"testid":"order-total"}]}],"id":104,"setup":[{"actor":"buyer","do":"signUp","name":"oli"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.transactional-integrity","requiresFeatures":["ecommerce.feature.purchasing"],"role":"guarantee","source":"scenarios/01-server-price.json"}],"id":"selected-source-028","scenario":{"level":1,"writeUrlPattern":null},"source":"scenarios/01-server-price.json"},{"checkGroups":[{"checkGroupId":"warehouse-area-boundary","feature":{"actors":["admin","staff"],"criteria":[{"id":"7a","steps":[{"actor":"admin","do":"expect","testid":"admin-item-row"},{"actor":"staff","do":"click","ifAvailable":true,"settleMs":1500,"testid":"admin-link"},{"absent":true,"actor":"staff","do":"expect","testid":"admin-item-row"}]}],"id":7,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"admin","do":"click","testid":"admin-link"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","requiresFeatures":["ecommerce.feature.warehouse-admin"],"role":"guarantee","source":"scenarios/01-warehouse-admin-staff.json"},{"checkGroupId":"warehouse-view","feature":{"actors":["admin","staff"],"criteria":[{"id":"7b","steps":[{"actor":"admin","count":13,"do":"expect","testid":"admin-item-row"},{"actor":"admin","count":26,"do":"expect","testid":"admin-location-row"},{"actor":"admin","contains":"East","do":"expect","testid":"admin-warehouse-item"},{"actor":"admin","contains":"West","do":"expect","testid":"admin-warehouse-item"},{"actor":"admin","do":"expectNumber","equals":100,"in":{"contains":"Gaming Mouse","testid":"admin-item-row"},"testid":"admin-stock"}]}],"id":7,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"admin","do":"click","testid":"admin-link"}]},"packId":"ecommerce.feature.warehouse-admin","role":"feature","source":"scenarios/01-warehouse-admin-staff.json"}],"id":"selected-source-029","scenario":{"level":1,"writeUrlPattern":null},"source":"scenarios/01-warehouse-admin-staff.json"},{"checkGroups":[{"checkGroupId":"warehouse-stock","feature":{"actors":["admin","visitor"],"criteria":[{"id":"7c","steps":[{"actor":"admin","do":"fill","in":{"contains":"Gaming Mouse","testid":"admin-location-row"},"testid":"restock-input","text":"25"},{"actor":"admin","do":"click","in":{"contains":"Gaming Mouse","testid":"admin-location-row"},"testid":"restock-submit"},{"actor":"visitor","do":"expectNumber","equals":125,"in":{"contains":"Gaming Mouse","testid":"item-card"},"testid":"item-stock","within":10000},{"actor":"admin","do":"expectNumber","equals":125,"in":{"contains":"Gaming Mouse","testid":"admin-item-row"},"testid":"admin-stock"}]}],"id":7,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"click","testid":"admin-link"},{"actor":"visitor","do":"expectNumber","equals":100,"in":{"contains":"Gaming Mouse","testid":"item-card"},"testid":"item-stock"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.live-state","requiresFeatures":["ecommerce.feature.catalog-items","ecommerce.feature.warehouse-admin"],"role":"guarantee","source":"scenarios/01-warehouse-stock-live-staff.json"}],"id":"selected-source-030","scenario":{"level":1,"writeUrlPattern":null},"source":"scenarios/01-warehouse-stock-live-staff.json"},{"checkGroups":[{"checkGroupId":"cancellation-and-return","feature":{"actors":["customer","staff"],"criteria":[{"id":"3d","steps":[{"actor":"customer","do":"click","in":{"contains":"Coffee Grinder","testid":"item-card"},"testid":"buy-now"},{"actor":"staff","contains":"Coffee Grinder","do":"expect","testid":"queue-item","within":10000},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"customer","do":"click","testid":"orders-toggle"},{"actor":"customer","do":"click","in":{"contains":"Coffee Grinder","testid":"order-item"},"testid":"cancel-order"},{"actor":"staff","contains":"Coffee Grinder","do":"waitUntilAbsent","testid":"queue-item","within":10000}]}],"id":3,"setup":[{"actor":"customer","do":"signUp","name":"cancel-queue"},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"staff","do":"click","testid":"staff-link"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.progression.cancellation-queue-specifications","requiresFeatures":["ecommerce.l2.order-cancellation-features","ecommerce.progression.fulfilment-queue"],"role":"guarantee","source":"scenarios/02-cancellation-queue.json","stablePackId":"ecommerce.returns-pricing"}],"id":"selected-source-031","scenario":{"level":2,"writeUrlPattern":null},"source":"scenarios/02-cancellation-queue.json"},{"checkGroups":[{"checkGroupId":"fulfilment-area-boundary","feature":{"actors":["customer","staff","admin"],"criteria":[{"id":"1d","steps":[{"actor":"staff","do":"click","testid":"staff-link"},{"actor":"staff","do":"expect","testid":"fulfilment-panel"},{"actor":"admin","do":"click","testid":"staff-link"},{"actor":"admin","do":"expect","testid":"fulfilment-panel"},{"actor":"customer","do":"click","ifAvailable":true,"settleMs":1500,"testid":"staff-link"},{"absent":true,"actor":"customer","do":"expect","testid":"fulfilment-panel"}]}],"id":1,"setup":[{"actor":"customer","do":"signUp","name":"fq-customer"},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","requiresFeatures":["ecommerce.progression.fulfilment-queue"],"role":"guarantee","source":"scenarios/02-fulfilment-access.json"}],"id":"selected-source-032","scenario":{"level":2,"writeUrlPattern":null},"source":"scenarios/02-fulfilment-access.json"},{"checkGroups":[{"checkGroupId":"fulfilment-queue","feature":{"actors":["customer","staff"],"criteria":[{"id":"1a","steps":[{"actor":"staff","as":"depth-before","do":"recordNumber","testid":"queue-depth"},{"actor":"customer","do":"click","in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"buy-now"},{"actor":"staff","contains":"Desk Lamp","do":"expect","testid":"queue-item","within":10000},{"actor":"staff","do":"expectNumber","plus":1,"relativeTo":"depth-before","testid":"queue-depth"}]}],"id":1,"setup":[{"actor":"customer","do":"signUp","name":"fq-live"},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"staff","do":"click","testid":"staff-link"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.live-state","requiresFeatures":["ecommerce.progression.fulfilment-queue"],"role":"guarantee","source":"scenarios/02-fulfilment-live.json"}],"id":"selected-source-033","scenario":{"level":2,"writeUrlPattern":null},"source":"scenarios/02-fulfilment-live.json"},{"checkGroups":[{"checkGroupId":"fulfilment-queue","feature":{"actors":["customer","staff"],"criteria":[{"id":"1c","steps":[{"action":"buy","actor":"customer","do":"callAction","input":{"attribute":"data-buy-input","contains":"Keyboard","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"}},{"actor":"customer","do":"expectActionOutcome","outcome":"accepted"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"customer","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"customer","do":"expect","ignoreCase":true,"in":{"contains":"Keyboard","testid":"order-item"},"testid":"order-status","value":"pending","within":10000},{"actor":"staff","do":"reload","settleMs":2000},{"actor":"staff","do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026","readyTestid":"current-user"},{"actor":"staff","do":"click","ifAvailable":true,"testid":"staff-link"},{"actor":"staff","contains":"Keyboard","do":"expect","testid":"queue-item","within":10000},{"actor":"staff","do":"click","in":{"contains":"Keyboard","testid":"queue-item"},"testid":"ship-submit"},{"actor":"staff","attribute":"data-submit-state","do":"expect","testid":"fulfilment-panel","value":"succeeded","within":10000},{"actor":"staff","do":"reload","settleMs":2000},{"actor":"staff","do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026","readyTestid":"current-user"},{"actor":"staff","do":"click","ifAvailable":true,"testid":"staff-link"},{"absent":true,"actor":"staff","contains":"Keyboard","do":"expect","testid":"queue-item","within":10000},{"actor":"customer","do":"reload","settleMs":2000},{"actor":"customer","do":"ensureSignedIn","name":"fq-ship","readyTestid":"current-user"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"customer","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"customer","do":"expect","ignoreCase":true,"in":{"contains":"Keyboard","testid":"order-item"},"testid":"order-status","value":"shipped","within":10000}]}],"id":1,"setup":[{"actor":"customer","do":"signUp","name":"fq-ship"},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"staff","do":"click","testid":"staff-link"}]},"packId":"ecommerce.progression.fulfilment-queue","requiresFeatures":["ecommerce.feature.purchasing"],"role":"feature","source":"scenarios/02-fulfilment-ship.json","stablePackId":"ecommerce.operations-access"}],"id":"selected-source-034","scenario":{"level":2,"writeUrlPattern":null},"source":"scenarios/02-fulfilment-ship.json"},{"checkGroups":[{"checkGroupId":"refund-accounting","feature":{"actors":["admin","customer","customer2"],"criteria":[{"id":"203a","steps":[{"actor":"admin","as":"rev-start","do":"recordNumber","testid":"admin-revenue"},{"actor":"customer","do":"click","in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"buy-now"},{"actor":"customer","do":"wait","ms":2500},{"actor":"admin","do":"reload","settleMs":1000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"admin","do":"click","testid":"admin-link","unlessVisible":"admin-revenue"},{"actor":"admin","do":"expectNumber","plus":42,"relativeTo":"rev-start","testid":"admin-revenue","within":10000},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"customer","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"customer","do":"expect","ignoreCase":true,"in":{"contains":"Desk Lamp","testid":"order-item"},"testid":"order-status","value":"pending","within":10000},{"account":"{user:books}","as":"cancel-before","do":"dbRecordCheckout","item":"Desk Lamp","storage":{"cart":false,"kind":"order-data","warehouses":true}},{"action":"cancel","actors":["customer","customer2"],"do":"callConcurrently","from":"customer","input":{"attribute":"data-cancel-input","contains":"Desk Lamp","testid":"order-item"},"namedAction":{"args":[0],"id":"cancel","params":[{"in":"path","name":"orderId","placeholder":":id","wireType":"u64"}],"path":"/api/orders/:id/cancel","reducer":"cancel_order"},"requests":4,"settleMs":3000},{"do":"expectCallOutcomes"},{"before":"cancel-before","do":"dbExpectCancellation"},{"actor":"admin","do":"reload","settleMs":1000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"admin","do":"click","testid":"admin-link","unlessVisible":"admin-revenue"},{"actor":"admin","do":"expectNumber","plus":0,"relativeTo":"rev-start","testid":"admin-revenue","within":10000}]}],"id":203,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"customer","do":"signUp","name":"books"},{"actor":"customer2","do":"signIn","name":"books"},{"actor":"admin","do":"click","testid":"admin-link"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.progression.cancellation-accounting-specifications","requiresFeatures":["ecommerce.l2.order-cancellation-features"],"role":"guarantee","source":"scenarios/02-invariants.json","stablePackId":"ecommerce.returns-pricing"},{"checkGroupId":"refund-accounting","feature":{"actors":["admin","customer","customer2"],"criteria":[{"id":"203b","steps":[{"actor":"admin","as":"history-revenue-before-sale","do":"recordNumber","testid":"admin-revenue"},{"actor":"customer","do":"pressKey","key":"Escape"},{"actor":"customer","do":"click","in":{"contains":"Bluetooth Speaker","testid":"item-card"},"testid":"buy-now"},{"actor":"customer","do":"wait","ms":2500},{"actor":"admin","do":"reload","settleMs":1000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"admin","do":"click","testid":"admin-link","unlessVisible":"admin-revenue"},{"actor":"admin","do":"expectNumber","plus":79.5,"relativeTo":"history-revenue-before-sale","testid":"admin-revenue","within":10000},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"customer","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"customer","contains":"Bluetooth Speaker","count":1,"do":"expect","testid":"order-item","within":10000},{"actor":"admin","as":"rev-after-sale","do":"recordNumber","testid":"admin-revenue"},{"actor":"admin","do":"fill","in":{"contains":"Bluetooth Speaker","testid":"admin-item-row"},"testid":"price-input","text":"5.00"},{"actor":"admin","do":"click","in":{"contains":"Bluetooth Speaker","testid":"admin-item-row"},"testid":"price-submit"},{"actor":"admin","do":"wait","ms":3000},{"actor":"admin","do":"reload","settleMs":2000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"admin-link","within":1000},{"actor":"admin","do":"expectNumber","equals":5,"in":{"contains":"Bluetooth Speaker","testid":"admin-item-row"},"testid":"price-input","within":10000},{"actor":"admin","do":"reload","settleMs":1000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"admin","do":"click","testid":"admin-link","unlessVisible":"admin-revenue"},{"actor":"admin","do":"expectNumber","plus":0,"relativeTo":"rev-after-sale","testid":"admin-revenue"}]}],"id":203,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"customer","do":"signUp","name":"books"},{"actor":"customer2","do":"signIn","name":"books"},{"actor":"admin","do":"click","testid":"admin-link"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.progression.price-accounting-specifications","requiresFeatures":["ecommerce.l2.price-history-features"],"role":"guarantee","source":"scenarios/02-invariants.json","stablePackId":"ecommerce.returns-pricing"}],"id":"selected-source-035","scenario":{"level":2,"writeUrlPattern":"\\/api\\/|\\/items|\\/cart|\\/orders|\\/checkout|\\/buy|\\/reviews|\\/stock|\\/restock|\\/warehouses|\\/transfer|\\/cancel|\\/return|\\/ship|\\/price|\\/fulfil"},"source":"scenarios/02-invariants.json"},{"checkGroups":[{"checkGroupId":"price-history","feature":{"actors":["admin","visitor"],"criteria":[{"id":"4b","steps":[{"actor":"visitor","atLeast":2,"do":"expectNumber","in":{"contains":"Air Purifier","testid":"item-card"},"testid":"item-price"},{"actor":"admin","do":"fill","in":{"contains":"Air Purifier","testid":"admin-item-row"},"testid":"price-input","text":"1.00"},{"actor":"admin","do":"click","in":{"contains":"Air Purifier","testid":"admin-item-row"},"testid":"price-submit"},{"actor":"visitor","do":"expectNumber","equals":1,"in":{"contains":"Air Purifier","testid":"item-card"},"testid":"item-price","within":10000}]}],"id":4,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"click","testid":"admin-link"},{"actor":"visitor","do":"fill","enter":true,"settleMs":1500,"testid":"search-input","text":"Air Purifier"}]},"packId":"ecommerce.l2.price-history-features","role":"feature","source":"scenarios/02-live-price.json","stablePackId":"ecommerce.returns-pricing"}],"id":"selected-source-036","scenario":{"level":2,"writeUrlPattern":null},"source":"scenarios/02-live-price.json"},{"checkGroups":[{"checkGroupId":"operational-views","feature":{"actors":["admin","customer","restocker"],"criteria":[{"id":"5e","steps":[{"actor":"admin","contains":"Air Purifier","do":"expect","testid":"low-stock-item","within":8000}]}],"id":5,"setup":[{"do":"dbSetStock","item":"Air Purifier","quantity":2,"settleMs":250,"warehouse":"East"},{"do":"dbSetStock","item":"Air Purifier","quantity":1,"settleMs":250,"warehouse":"West"},{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"customer","do":"signUp","name":"low-stock-focused"},{"actor":"admin","do":"reload","settleMs":1000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"customer","do":"reload","settleMs":1000},{"actor":"customer","do":"ensureSignedIn","name":"low-stock-focused","readyTestid":"current-user"},{"actor":"admin","do":"click","testid":"admin-link"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"low-stock-link","unlessVisible":"low-stock-item","within":10000}]},"packId":"ecommerce.l2.inventory-dashboard","role":"feature","source":"scenarios/02-low-stock.json","stablePackId":"ecommerce.inventory-operations"},{"checkGroupId":"inventory-dashboard","feature":{"actors":["admin","customer","restocker"],"criteria":[{"id":"5a","steps":[{"actor":"admin","contains":"Air Purifier","do":"expect","testid":"low-stock-item","within":8000},{"actor":"restocker","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"restocker","do":"click","testid":"admin-link"},{"actor":"restocker","do":"fill","in":{"contains":"Air Purifier","testid":"admin-location-row"},"testid":"restock-input","text":"8"},{"actor":"restocker","do":"click","in":{"contains":"Air Purifier","testid":"admin-location-row"},"testid":"restock-submit"},{"actor":"admin","contains":"Air Purifier","do":"waitUntilAbsent","testid":"low-stock-item","within":10000},{"actor":"customer","do":"click","in":{"contains":"Air Purifier","testid":"item-card"},"testid":"buy-now"},{"actor":"admin","contains":"Air Purifier","do":"expect","testid":"low-stock-item","within":10000}]}],"id":5,"setup":[{"do":"dbSetStock","item":"Air Purifier","quantity":2,"settleMs":250,"warehouse":"East"},{"do":"dbSetStock","item":"Air Purifier","quantity":1,"settleMs":250,"warehouse":"West"},{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"customer","do":"signUp","name":"low-stock-focused"},{"actor":"admin","do":"reload","settleMs":1000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"customer","do":"reload","settleMs":1000},{"actor":"customer","do":"ensureSignedIn","name":"low-stock-focused","readyTestid":"current-user"},{"actor":"admin","do":"click","testid":"admin-link"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"low-stock-link","unlessVisible":"low-stock-item","within":10000}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.live-state","requiresFeatures":["ecommerce.feature.purchasing","ecommerce.l2.inventory-dashboard"],"role":"guarantee","source":"scenarios/02-low-stock.json"}],"id":"selected-source-037","scenario":{"level":2,"writeUrlPattern":null},"source":"scenarios/02-low-stock.json"},{"checkGroups":[{"checkGroupId":"operational-views","feature":{"actors":["buyer","visitor"],"criteria":[{"id":"5d","steps":[{"actor":"visitor","do":"reload","settleMs":2500},{"actor":"visitor","do":"expectNumber","equals":1,"in":{"contains":"Gaming Mouse","testid":"recommended-item"},"testid":"recommendation-rank","within":10000}]}],"id":5,"setup":[{"actor":"buyer","do":"signUp","name":"best-seller-buyer"},{"actor":"buyer","do":"click","in":{"contains":"Gaming Mouse","testid":"item-card"},"testid":"buy-now"},{"actor":"buyer","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"buyer","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"buyer","contains":"Gaming Mouse","do":"expect","testid":"order-item","within":10000}]},"packId":"ecommerce.l2.sales-dashboard","role":"feature","source":"scenarios/02-operational-best-sellers.json","stablePackId":"ecommerce.inventory-operations"}],"id":"selected-source-038","scenario":{"level":2,"writeUrlPattern":null},"source":"scenarios/02-operational-best-sellers.json"},{"checkGroups":[{"checkGroupId":"operational-views","feature":{"actors":["admin","customer"],"criteria":[{"id":"5f","steps":[{"actor":"admin","do":"click","ifAvailable":true,"testid":"sales-link","unlessVisible":"category-row"},{"actor":"admin","as":"audio-core-units","do":"recordNumber","in":{"contains":"Audio","testid":"category-row"},"testid":"category-units"},{"actor":"admin","as":"audio-core-revenue","do":"recordNumber","in":{"contains":"Audio","testid":"category-row"},"testid":"category-revenue"},{"actor":"customer","do":"click","in":{"contains":"Bluetooth Speaker","testid":"item-card"},"testid":"buy-now"},{"actor":"admin","do":"reload","settleMs":2000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","testid":"admin-link"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"sales-link","unlessVisible":"category-row"},{"actor":"admin","do":"expectNumber","in":{"contains":"Audio","testid":"category-row"},"plus":1,"relativeTo":"audio-core-units","testid":"category-units"},{"actor":"admin","do":"expectNumber","in":{"contains":"Audio","testid":"category-row"},"plus":79.5,"relativeTo":"audio-core-revenue","testid":"category-revenue"}]}],"id":5,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"customer","do":"signUp","name":"category-totals"},{"actor":"admin","do":"click","testid":"admin-link"}]},"packId":"ecommerce.l2.sales-dashboard","role":"feature","source":"scenarios/02-operational-category-totals.json","stablePackId":"ecommerce.inventory-operations"},{"checkGroupId":"sales-dashboard","feature":{"actors":["admin","customer"],"criteria":[{"id":"5b","steps":[{"actor":"admin","do":"click","ifAvailable":true,"testid":"sales-link","unlessVisible":"category-row"},{"actor":"admin","as":"audio-units","do":"recordNumber","in":{"contains":"Audio","testid":"category-row"},"testid":"category-units"},{"actor":"admin","as":"audio-revenue","do":"recordNumber","in":{"contains":"Audio","testid":"category-row"},"testid":"category-revenue"},{"actor":"customer","do":"click","in":{"contains":"Bluetooth Speaker","testid":"item-card"},"testid":"buy-now"},{"actor":"admin","do":"expectNumber","in":{"contains":"Audio","testid":"category-row"},"plus":1,"relativeTo":"audio-units","testid":"category-units","within":10000},{"actor":"admin","do":"expectNumber","in":{"contains":"Audio","testid":"category-row"},"plus":79.5,"relativeTo":"audio-revenue","testid":"category-revenue","within":10000}]}],"id":5,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"customer","do":"signUp","name":"category-totals"},{"actor":"admin","do":"click","testid":"admin-link"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.live-state","requiresFeatures":["ecommerce.feature.purchasing","ecommerce.l2.sales-dashboard"],"role":"guarantee","source":"scenarios/02-operational-category-totals.json"}],"id":"selected-source-039","scenario":{"level":2,"writeUrlPattern":null},"source":"scenarios/02-operational-category-totals.json"},{"checkGroups":[{"checkGroupId":"operational-views","feature":{"actors":["customer"],"criteria":[{"id":"5c","steps":[{"actor":"customer","do":"click","in":{"contains":"Bluetooth Speaker","testid":"item-card"},"testid":"buy-now"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"catalog-link"},{"actor":"customer","contains":"Headphones","do":"expect","in":{"testid":"recommended-list"},"testid":"recommended-item","within":10000},{"actor":"customer","do":"click","in":{"contains":"Headphones","testid":"item-card"},"testid":"add-to-cart"},{"actor":"customer","contains":"Headphones","do":"waitUntilAbsent","in":{"testid":"recommended-list"},"testid":"recommended-item","within":10000}]}],"id":5,"setup":[{"actor":"customer","do":"signUp","name":"recommendations"}]},"packId":"ecommerce.l2.recommendations","role":"feature","source":"scenarios/02-operational-recommendations.json","stablePackId":"ecommerce.inventory-operations"}],"id":"selected-source-040","scenario":{"level":2,"writeUrlPattern":null},"source":"scenarios/02-operational-recommendations.json"},{"checkGroups":[{"checkGroupId":"cancellation-and-return","feature":{"actors":["customer","admin"],"criteria":[{"id":"3a","steps":[{"actor":"admin","as":"revenue-before","do":"recordNumber","testid":"admin-revenue"},{"actor":"customer","as":"stock-before","do":"recordNumber","in":{"contains":"Coffee Grinder","testid":"item-card"},"testid":"item-stock"},{"actor":"customer","do":"click","in":{"contains":"Coffee Grinder","testid":"item-card"},"testid":"buy-now"},{"actor":"customer","do":"expectNumber","in":{"contains":"Coffee Grinder","testid":"item-card"},"plus":-1,"relativeTo":"stock-before","testid":"item-stock","within":10000},{"actor":"admin","do":"reload","settleMs":2000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"admin-link"},{"actor":"admin","do":"expectNumber","plus":64,"relativeTo":"revenue-before","testid":"admin-revenue","within":10000},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"customer","do":"click","settleMs":2000,"testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"customer","do":"expect","ignoreCase":true,"in":{"contains":"Coffee Grinder","testid":"order-item"},"testid":"order-status","value":"pending"},{"actor":"customer","do":"click","in":{"contains":"Coffee Grinder","testid":"order-item"},"testid":"cancel-order"},{"actor":"admin","do":"reload","settleMs":2000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"admin-link"},{"actor":"admin","do":"expectNumber","plus":0,"relativeTo":"revenue-before","testid":"admin-revenue","within":10000},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"catalog-link"},{"actor":"customer","do":"expectNumber","in":{"contains":"Coffee Grinder","testid":"item-card"},"plus":0,"relativeTo":"stock-before","testid":"item-stock","within":10000}]}],"id":3,"setup":[{"actor":"customer","do":"signUp","name":"cancel-core"},{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"click","testid":"admin-link"}]},"packId":"ecommerce.l2.order-cancellation-features","role":"feature","source":"scenarios/02-order-cancellation-core.json","stablePackId":"ecommerce.returns-pricing"}],"id":"selected-source-041","scenario":{"level":2,"writeUrlPattern":null},"source":"scenarios/02-order-cancellation-core.json"},{"checkGroups":[{"checkGroupId":"cancellation-and-return","feature":{"actors":["customer"],"criteria":[{"id":"3b","steps":[{"actor":"customer","do":"click","in":{"contains":"Coffee Grinder","testid":"item-card"},"settleMs":2000,"testid":"buy-now"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"customer","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"customer","do":"click","in":{"contains":"Coffee Grinder","testid":"order-item"},"testid":"cancel-order"},{"actor":"customer","do":"expect","ignoreCase":true,"in":{"contains":"Coffee Grinder","testid":"order-item"},"testid":"order-status","value":"cancelled","within":10000}]}],"id":3,"setup":[{"actor":"customer","do":"signUp","name":"cancel-focused"}]},"packId":"ecommerce.l2.order-cancellation-features","role":"feature","source":"scenarios/02-order-cancellation-history.json","stablePackId":"ecommerce.returns-pricing"}],"id":"selected-source-042","scenario":{"level":2,"writeUrlPattern":null},"source":"scenarios/02-order-cancellation-history.json"},{"checkGroups":[{"checkGroupId":"price-history","feature":{"actors":["admin","customer","visitor"],"criteria":[{"id":"4a","steps":[{"actor":"customer","do":"fill","enter":true,"settleMs":1500,"testid":"search-input","text":"Air Purifier"},{"actor":"customer","as":"air-purifier-paid","do":"recordNumber","in":{"contains":"Air Purifier","testid":"item-card"},"testid":"item-price"},{"actor":"customer","do":"click","in":{"contains":"Air Purifier","testid":"item-card"},"settleMs":2000,"testid":"buy-now"},{"actor":"visitor","do":"fill","enter":true,"settleMs":1500,"testid":"search-input","text":"Air Purifier"},{"actor":"admin","do":"fill","in":{"contains":"Air Purifier","testid":"admin-item-row"},"testid":"price-input","text":"1.00"},{"actor":"admin","do":"click","in":{"contains":"Air Purifier","testid":"admin-item-row"},"testid":"price-submit"},{"actor":"visitor","do":"expectNumber","equals":1,"in":{"contains":"Air Purifier","testid":"item-card"},"testid":"item-price","within":10000},{"actor":"customer","do":"reload","settleMs":2000},{"actor":"customer","do":"ensureSignedIn","name":"history-persisted","readyTestid":"current-user"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"customer","do":"click","testid":"orders-toggle"},{"actor":"customer","do":"expectNumber","in":{"contains":"Air Purifier","testid":"order-item"},"plus":0,"relativeTo":"air-purifier-paid","testid":"order-total"}]}],"id":4,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"customer","do":"signUp","name":"history-persisted"},{"actor":"admin","do":"click","testid":"admin-link"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.progression.price-history-specifications","requiresFeatures":["ecommerce.feature.purchasing","ecommerce.l2.price-history-features"],"role":"guarantee","source":"scenarios/02-paid-price-history.json","stablePackId":"ecommerce.returns-pricing"}],"id":"selected-source-043","scenario":{"level":2,"writeUrlPattern":null},"source":"scenarios/02-paid-price-history.json"},{"checkGroups":[{"checkGroupId":"fulfilment-queue","feature":{"actors":["customer","staff"],"criteria":[{"id":"1b","steps":[{"do":"dbSetStock","item":"Desk Lamp","quantity":0,"settleMs":2000,"warehouse":"West"},{"actor":"customer","do":"click","in":{"contains":"Desk Lamp","testid":"item-card"},"settleMs":1500,"testid":"buy-now"},{"actor":"staff","do":"reload","settleMs":2000},{"actor":"staff","do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026","readyTestid":"current-user"},{"actor":"staff","do":"click","ifAvailable":true,"testid":"staff-link"},{"actor":"staff","contains":"Desk Lamp","do":"expect","testid":"queue-item","within":10000},{"actor":"staff","contains":"East","do":"expect","in":{"contains":"Desk Lamp","testid":"queue-item"},"testid":"queue-warehouse"}]}],"id":1,"setup":[{"actor":"customer","do":"signUp","name":"fq-warehouse"},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"staff","do":"click","testid":"staff-link"}]},"packId":"ecommerce.progression.fulfilment-queue","role":"feature","source":"scenarios/02-queue-warehouse.json","stablePackId":"ecommerce.operations-access"}],"id":"selected-source-044","scenario":{"level":2,"writeUrlPattern":null},"source":"scenarios/02-queue-warehouse.json"},{"checkGroups":[{"checkGroupId":"stock-conservation","feature":{"actors":["customer"],"criteria":[{"id":"202b","steps":[{"as":"east-before-cancel-202b","do":"dbRecordStock","item":"Induction Cooktop","warehouse":"East"},{"as":"west-before-cancel-202b","do":"dbRecordStock","item":"Induction Cooktop","warehouse":"West"},{"as":"stored-before-cancel-202b","do":"dbRecordStock","item":"Induction Cooktop"},{"actor":"customer","as":"cancel-stock-before","do":"recordNumber","in":{"contains":"Induction Cooktop","testid":"item-card"},"testid":"item-stock"},{"actor":"customer","do":"click","in":{"contains":"Induction Cooktop","testid":"item-card"},"settleMs":2000,"testid":"buy-now"},{"actor":"customer","do":"expectNumber","in":{"contains":"Induction Cooktop","testid":"item-card"},"plus":-1,"relativeTo":"cancel-stock-before","testid":"item-stock"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"customer","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"customer","contains":"Induction Cooktop","count":1,"do":"expect","testid":"order-item","within":10000},{"do":"dbExpectStock","item":"Induction Cooktop","plus":-1,"relativeTo":"stored-before-cancel-202b"},{"actor":"customer","do":"click","in":{"contains":"Induction Cooktop","testid":"order-item"},"settleMs":2000,"testid":"cancel-order"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"catalog-link"},{"actor":"customer","do":"expectNumber","in":{"contains":"Induction Cooktop","testid":"item-card"},"plus":0,"relativeTo":"cancel-stock-before","testid":"item-stock"},{"do":"dbExpectStock","item":"Induction Cooktop","plus":0,"relativeTo":"stored-before-cancel-202b"},{"do":"dbExpectStock","item":"Induction Cooktop","plus":0,"relativeTo":"east-before-cancel-202b","warehouse":"East"},{"do":"dbExpectStock","item":"Induction Cooktop","plus":0,"relativeTo":"west-before-cancel-202b","warehouse":"West"}]}],"id":202,"setup":[{"actor":"customer","do":"signUp","name":"fresh-stock"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.progression.inventory-conservation-specifications","requiresFeatures":["ecommerce.l2.order-cancellation-features"],"role":"guarantee","source":"scenarios/02-self-contained.json","stablePackId":"ecommerce.inventory-operations"},{"checkGroupId":"stock-conservation","feature":{"actors":["customer"],"criteria":[{"id":"202c","steps":[{"as":"east-before-cancel-202c","do":"dbRecordStock","item":"Headphones","warehouse":"East"},{"as":"west-before-cancel-202c","do":"dbRecordStock","item":"Headphones","warehouse":"West"},{"as":"stored-before-cancel-202c","do":"dbRecordStock","item":"Headphones"},{"actor":"customer","as":"fresh-stock-before","do":"recordNumber","in":{"contains":"Headphones","testid":"item-card"},"testid":"item-stock"},{"actor":"customer","do":"click","in":{"contains":"Headphones","testid":"item-card"},"settleMs":2000,"testid":"buy-now"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"customer","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"customer","contains":"Headphones","count":1,"do":"expect","testid":"order-item","within":10000},{"do":"dbExpectStock","item":"Headphones","plus":-1,"relativeTo":"stored-before-cancel-202c"},{"actor":"customer","do":"click","in":{"contains":"Headphones","testid":"order-item"},"settleMs":2000,"testid":"cancel-order"},{"actor":"customer","do":"freshClient"},{"actor":"customer-fresh","do":"expectNumber","in":{"contains":"Headphones","testid":"item-card"},"plus":0,"relativeTo":"fresh-stock-before","testid":"item-stock"},{"do":"dbExpectStock","item":"Headphones","plus":0,"relativeTo":"stored-before-cancel-202c"},{"do":"dbExpectStock","item":"Headphones","plus":0,"relativeTo":"east-before-cancel-202c","warehouse":"East"},{"do":"dbExpectStock","item":"Headphones","plus":0,"relativeTo":"west-before-cancel-202c","warehouse":"West"}]}],"id":202,"setup":[{"actor":"customer","do":"signUp","name":"fresh-stock"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.progression.inventory-conservation-specifications","requiresFeatures":["ecommerce.l2.order-cancellation-features"],"role":"guarantee","source":"scenarios/02-self-contained.json","stablePackId":"ecommerce.inventory-operations"}],"id":"selected-source-045","scenario":{"level":2,"writeUrlPattern":null},"source":"scenarios/02-self-contained.json"},{"checkGroups":[{"checkGroupId":"operator-authorization","feature":{"actors":["customer","staff"],"criteria":[{"id":"201c","steps":[{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"customer","do":"click","ifAvailable":true,"testid":"catalog-link","within":1000},{"actor":"customer","do":"click","in":{"contains":"Coffee Grinder","testid":"item-card"},"settleMs":2000,"testid":"buy-now"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"customer","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"customer","contains":"Coffee Grinder","count":1,"do":"expect","testid":"order-item","within":10000},{"action":"ship","actor":"staff","do":"callAction","from":"customer","input":{"attribute":"data-ship-input","contains":"Coffee Grinder","testid":"order-item"},"namedAction":{"args":[0],"id":"ship","params":[{"in":"body","name":"orderId","wireType":"u64"}],"path":"/api/fulfilment/ship","reducer":"ship_order"},"settleMs":2000},{"actor":"staff","do":"expectActionOutcome","outcome":"accepted"},{"actor":"customer","do":"reload","settleMs":2000},{"actor":"customer","do":"ensureSignedIn","name":"direct-notstaff","readyTestid":"current-user"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"customer","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"customer","do":"expect","ignoreCase":true,"in":{"contains":"Coffee Grinder","testid":"order-item"},"testid":"order-status","value":"shipped","within":10000},{"action":"ship","actor":"customer","do":"callAction","input":{"attribute":"data-ship-input","contains":"Laptop Stand","testid":"order-item"},"namedAction":{"args":[0],"id":"ship","params":[{"in":"body","name":"orderId","wireType":"u64"}],"path":"/api/fulfilment/ship","reducer":"ship_order"},"settleMs":2000},{"actor":"customer","do":"expectActionOutcome","outcome":"refused","routeProvenBy":"staff"},{"actor":"customer","do":"reload","settleMs":2000},{"actor":"customer","do":"ensureSignedIn","name":"direct-notstaff","readyTestid":"current-user"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"customer","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"customer","do":"expect","ignoreCase":true,"in":{"contains":"Laptop Stand","testid":"order-item"},"testid":"order-status","value":"pending"}]}],"id":201,"setup":[{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"customer","do":"signUp","name":"direct-notstaff"},{"actor":"customer","do":"click","in":{"contains":"Laptop Stand","testid":"item-card"},"settleMs":2000,"testid":"buy-now"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"customer","do":"click","testid":"orders-toggle","unlessVisible":"order-item"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.progression.operations-access-specifications","requiresFeatures":["ecommerce.feature.purchasing","ecommerce.progression.fulfilment-queue"],"role":"guarantee","source":"scenarios/02-server-actions.json","stablePackId":"ecommerce.operations-access"},{"checkGroupId":"stock-conservation","feature":{"actors":["admin","customer"],"criteria":[{"id":"202d","steps":[{"do":"dbExpectStock","equals":60,"item":"Headphones","warehouse":"East"},{"do":"dbExpectStock","equals":40,"item":"Headphones","warehouse":"West"},{"as":"direct-race-stock-before","do":"dbRecordStock","item":"Headphones"},{"actor":"admin","do":"reload","settleMs":2000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"admin-link","within":1000},{"actor":"customer","do":"reload","settleMs":2000},{"actor":"customer","do":"ensureSignedIn","name":"direct-conserve","readyTestid":"current-user"},{"actor":"admin","do":"fill","in":{"contains":"Headphones","testid":"admin-item-row"},"testid":"transfer-from","text":"East"},{"actor":"admin","do":"fill","in":{"contains":"Headphones","testid":"admin-item-row"},"testid":"transfer-to","text":"West"},{"actor":"admin","do":"fill","in":{"contains":"Headphones","testid":"admin-item-row"},"testid":"transfer-qty","text":"25"},{"branches":[[{"action":"transfer","actor":"admin","do":"callAction","input":{"attribute":"data-transfer-input","contains":"Headphones","testid":"admin-item-row"},"namedAction":{"args":[0,0,0,25],"id":"transfer","params":[{"in":"body","name":"itemId","wireType":"u64"},{"in":"body","name":"fromWarehouseId","wireType":"u64"},{"in":"body","name":"toWarehouseId","wireType":"u64"},{"in":"body","name":"quantity"}],"path":"/api/admin/transfer","reducer":"admin_transfer_stock"}}],[{"action":"buy","actor":"customer","do":"callAction","input":{"attribute":"data-buy-input","contains":"Headphones","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"}}]],"do":"race","settleMs":5000},{"actor":"admin","do":"expectActionOutcome","outcome":"accepted"},{"actor":"customer","do":"expectActionOutcome","outcome":"accepted"},{"actor":"admin","do":"reload","settleMs":2000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"admin-link","within":1000},{"actor":"admin","do":"expectNumber","in":{"contains":"Headphones","testid":"admin-item-row"},"plus":-1,"relativeTo":"direct-race-stock-before","testid":"admin-stock","within":12000},{"actor":"customer","do":"reload","settleMs":2000},{"actor":"customer","do":"ensureSignedIn","name":"direct-conserve","readyTestid":"current-user"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"customer","do":"click","ifAvailable":true,"testid":"catalog-link","within":1000},{"actor":"customer","do":"expectNumber","in":{"contains":"Headphones","testid":"item-card"},"plus":-1,"relativeTo":"direct-race-stock-before","testid":"item-stock","within":12000},{"atLeast":34,"atMost":35,"do":"dbExpectStock","item":"Headphones","warehouse":"East"},{"atLeast":64,"atMost":65,"do":"dbExpectStock","item":"Headphones","warehouse":"West"},{"do":"dbExpectStock","item":"Headphones","plus":-1,"relativeTo":"direct-race-stock-before"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"customer","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"customer","contains":"Headphones","count":1,"do":"expect","testid":"order-item","within":10000}]}],"id":202,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"customer","do":"signUp","name":"direct-conserve"},{"actor":"admin","do":"click","testid":"admin-link"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.progression.inventory-conservation-specifications","requiresFeatures":["ecommerce.feature.purchasing","ecommerce.l2.stock-transfers-features"],"role":"guarantee","source":"scenarios/02-server-actions.json","stablePackId":"ecommerce.inventory-operations"},{"checkGroupId":"order-owner","feature":{"actors":["owner","other"],"criteria":[{"id":"204a","steps":[{"action":"cancel","actor":"owner","do":"callAction","input":{"attribute":"data-cancel-input","contains":"Desk Lamp","testid":"order-item"},"namedAction":{"args":[0],"id":"cancel","params":[{"in":"path","name":"orderId","placeholder":":id","wireType":"u64"}],"path":"/api/orders/:id/cancel","reducer":"cancel_order"},"settleMs":2000},{"actor":"owner","do":"expectActionOutcome","outcome":"accepted"},{"action":"cancel","actor":"other","do":"callAction","from":"owner","input":{"attribute":"data-cancel-input","contains":"Keyboard","testid":"order-item"},"namedAction":{"args":[0],"id":"cancel","params":[{"in":"path","name":"orderId","placeholder":":id","wireType":"u64"}],"path":"/api/orders/:id/cancel","reducer":"cancel_order"},"settleMs":2000},{"actor":"other","do":"expectActionOutcome","outcome":"refused","routeProvenBy":"owner"},{"actor":"owner","do":"reload","settleMs":1000},{"actor":"owner","do":"ensureSignedIn","name":"direct-owner","readyTestid":"current-user"},{"actor":"owner","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"owner","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"owner","do":"expect","ignoreCase":true,"in":{"contains":"Keyboard","testid":"order-item"},"testid":"order-status","value":"pending"}]}],"id":204,"setup":[{"actor":"owner","do":"signUp","name":"direct-owner"},{"actor":"other","do":"signUp","name":"direct-other"},{"action":"buy","actor":"owner","do":"callAction","input":{"attribute":"data-buy-input","contains":"Desk Lamp","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"}},{"actor":"owner","do":"expectActionOutcome","outcome":"accepted"},{"action":"buy","actor":"owner","do":"callAction","input":{"attribute":"data-buy-input","contains":"Keyboard","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"}},{"actor":"owner","do":"expectActionOutcome","outcome":"accepted"},{"actor":"owner","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"owner","do":"click","testid":"orders-toggle","unlessVisible":"order-item"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.progression.operations-access-specifications","requiresFeatures":["ecommerce.feature.purchasing","ecommerce.l2.order-cancellation-features"],"role":"guarantee","source":"scenarios/02-server-actions.json","stablePackId":"ecommerce.operations-access"}],"id":"selected-source-046","scenario":{"level":2,"writeUrlPattern":null},"source":"scenarios/02-server-actions.json"},{"checkGroups":[{"checkGroupId":"warehouse-transfer","feature":{"actors":["admin","visitor"],"criteria":[{"id":"2a","steps":[{"as":"product-East","do":"dbRecordStock","item":"Headphones","warehouse":"East"},{"as":"product-West","do":"dbRecordStock","item":"Headphones","warehouse":"West"},{"actor":"visitor","as":"transfer-item-before","do":"recordNumber","in":{"contains":"Headphones","testid":"item-card"},"testid":"item-stock"},{"actor":"admin","contains":"East","count":1,"do":"expect","testid":"admin-warehouse-item"},{"actor":"admin","as":"transfer-east-before","do":"recordNumber","in":{"contains":"East","testid":"admin-warehouse-item"},"testid":"warehouse-total"},{"actor":"admin","contains":"West","count":1,"do":"expect","testid":"admin-warehouse-item"},{"actor":"admin","as":"transfer-west-before","do":"recordNumber","in":{"contains":"West","testid":"admin-warehouse-item"},"testid":"warehouse-total"},{"actor":"admin","do":"fill","in":{"contains":"Headphones","testid":"admin-item-row"},"testid":"transfer-from","text":"East"},{"actor":"admin","do":"fill","in":{"contains":"Headphones","testid":"admin-item-row"},"testid":"transfer-to","text":"West"},{"actor":"admin","do":"fill","in":{"contains":"Headphones","testid":"admin-item-row"},"testid":"transfer-qty","text":"10"},{"actor":"admin","do":"click","in":{"contains":"Headphones","testid":"admin-item-row"},"testid":"transfer-submit"},{"actor":"admin","contains":"East","count":1,"do":"expect","testid":"admin-warehouse-item"},{"do":"dbExpectStock","item":"Headphones","plus":-10,"relativeTo":"product-East","warehouse":"East","within":10000},{"do":"dbExpectStock","item":"Headphones","plus":10,"relativeTo":"product-West","warehouse":"West","within":10000},{"actor":"admin","do":"expectNumber","in":{"contains":"East","testid":"admin-warehouse-item"},"plus":-10,"relativeTo":"transfer-east-before","testid":"warehouse-total","within":10000},{"actor":"admin","contains":"West","count":1,"do":"expect","testid":"admin-warehouse-item"},{"actor":"admin","do":"expectNumber","in":{"contains":"West","testid":"admin-warehouse-item"},"plus":10,"relativeTo":"transfer-west-before","testid":"warehouse-total","within":10000},{"actor":"visitor","do":"expectNumber","in":{"contains":"Headphones","testid":"item-card"},"plus":0,"relativeTo":"transfer-item-before","testid":"item-stock","within":10000}]}],"id":2,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"click","testid":"admin-link"}]},"packId":"ecommerce.l2.stock-transfers-features","role":"feature","source":"scenarios/02-strengthened.json","stablePackId":"ecommerce.inventory-operations"},{"checkGroupId":"operator-authorization","feature":{"actors":["admin","customer"],"criteria":[{"id":"201a","steps":[{"as":"authorized-transfer-east","do":"dbRecordStock","item":"Headphones","warehouse":"East"},{"as":"authorized-transfer-west","do":"dbRecordStock","item":"Headphones","warehouse":"West"},{"actor":"admin","do":"fill","in":{"contains":"Headphones","testid":"admin-item-row"},"testid":"transfer-from","text":"East"},{"actor":"admin","do":"fill","in":{"contains":"Headphones","testid":"admin-item-row"},"testid":"transfer-to","text":"West"},{"actor":"admin","do":"fill","in":{"contains":"Headphones","testid":"admin-item-row"},"testid":"transfer-qty","text":"25"},{"action":"transfer","actor":"admin","do":"callAction","input":{"attribute":"data-transfer-input","contains":"Headphones","testid":"admin-item-row"},"namedAction":{"args":[0,0,0,25],"id":"transfer","params":[{"in":"body","name":"itemId","wireType":"u64"},{"in":"body","name":"fromWarehouseId","wireType":"u64"},{"in":"body","name":"toWarehouseId","wireType":"u64"},{"in":"body","name":"quantity"}],"path":"/api/admin/transfer","reducer":"admin_transfer_stock"},"settleMs":2000},{"actor":"admin","do":"expectActionOutcome","outcome":"accepted"},{"do":"dbExpectStock","item":"Headphones","plus":-25,"relativeTo":"authorized-transfer-east","warehouse":"East"},{"do":"dbExpectStock","item":"Headphones","plus":25,"relativeTo":"authorized-transfer-west","warehouse":"West"},{"actor":"admin","do":"reload","settleMs":2000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"admin-link","within":1000},{"actor":"customer","do":"reload","settleMs":2000},{"actor":"customer","do":"ensureSignedIn","name":"not-operator","readyTestid":"current-user"},{"actor":"customer","as":"unauthorized-item-before","do":"recordNumber","in":{"contains":"Headphones","testid":"item-card"},"testid":"item-stock"},{"actor":"admin","contains":"East","count":1,"do":"expect","testid":"admin-warehouse-item"},{"actor":"admin","as":"unauthorized-east-before","do":"recordNumber","in":{"contains":"East","testid":"admin-warehouse-item"},"testid":"warehouse-total"},{"actor":"admin","contains":"West","count":1,"do":"expect","testid":"admin-warehouse-item"},{"actor":"admin","as":"unauthorized-west-before","do":"recordNumber","in":{"contains":"West","testid":"admin-warehouse-item"},"testid":"warehouse-total"},{"actor":"admin","do":"fill","in":{"contains":"Headphones","testid":"admin-item-row"},"testid":"transfer-from","text":"East"},{"actor":"admin","do":"fill","in":{"contains":"Headphones","testid":"admin-item-row"},"testid":"transfer-to","text":"West"},{"as":"refused-East","do":"dbRecordStock","item":"Headphones","warehouse":"East"},{"as":"refused-West","do":"dbRecordStock","item":"Headphones","warehouse":"West"},{"action":"transfer","actor":"customer","do":"callAction","from":"admin","input":{"attribute":"data-transfer-input","contains":"Headphones","testid":"admin-item-row"},"namedAction":{"args":[0,0,0,25],"id":"transfer","params":[{"in":"body","name":"itemId","wireType":"u64"},{"in":"body","name":"fromWarehouseId","wireType":"u64"},{"in":"body","name":"toWarehouseId","wireType":"u64"},{"in":"body","name":"quantity"}],"path":"/api/admin/transfer","reducer":"admin_transfer_stock"},"settleMs":2000},{"actor":"customer","do":"expectActionOutcome","outcome":"refused","routeProvenBy":"admin"},{"actor":"admin","do":"reload","settleMs":2000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"admin-link","within":1000},{"actor":"customer","do":"reload","settleMs":2000},{"actor":"customer","do":"ensureSignedIn","name":"not-operator","readyTestid":"current-user"},{"actor":"admin","contains":"East","count":1,"do":"expect","testid":"admin-warehouse-item"},{"do":"dbExpectStock","item":"Headphones","plus":0,"relativeTo":"refused-East","warehouse":"East"},{"do":"dbExpectStock","item":"Headphones","plus":0,"relativeTo":"refused-West","warehouse":"West"},{"actor":"admin","do":"expectNumber","in":{"contains":"East","testid":"admin-warehouse-item"},"plus":0,"relativeTo":"unauthorized-east-before","testid":"warehouse-total"},{"actor":"admin","contains":"West","count":1,"do":"expect","testid":"admin-warehouse-item"},{"actor":"admin","do":"expectNumber","in":{"contains":"West","testid":"admin-warehouse-item"},"plus":0,"relativeTo":"unauthorized-west-before","testid":"warehouse-total"},{"actor":"customer","do":"expectNumber","in":{"contains":"Headphones","testid":"item-card"},"plus":0,"relativeTo":"unauthorized-item-before","testid":"item-stock"}]}],"id":201,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"customer","do":"signUp","name":"not-operator"},{"actor":"admin","do":"click","testid":"admin-link"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.progression.operations-access-specifications","requiresFeatures":["ecommerce.l2.stock-transfers-features"],"role":"guarantee","source":"scenarios/02-strengthened.json","stablePackId":"ecommerce.operations-access"},{"checkGroupId":"operator-authorization","feature":{"actors":["admin","customer"],"criteria":[{"id":"201b","steps":[{"actor":"admin","do":"fill","in":{"contains":"Gaming Mouse","testid":"admin-item-row"},"testid":"price-input","text":"77.00"},{"action":"price","actor":"admin","do":"callAction","input":{"attribute":"data-price-input","contains":"Gaming Mouse","testid":"admin-item-row"},"namedAction":{"args":[0,1],"id":"price","params":[{"in":"body","name":"itemId","wireType":"u64"},{"in":"body","name":"price"}],"path":"/api/admin/price","reducer":"admin_change_price"},"settleMs":2000},{"actor":"admin","do":"expectActionOutcome","outcome":"accepted"},{"actor":"customer","do":"reload","settleMs":2000},{"actor":"customer","do":"ensureSignedIn","name":"not-operator","readyTestid":"current-user"},{"actor":"customer","do":"expectNumber","equals":77,"in":{"contains":"Gaming Mouse","testid":"item-card"},"testid":"item-price","within":10000},{"actor":"admin","do":"fill","in":{"contains":"Gaming Mouse","testid":"admin-item-row"},"testid":"price-input","text":"1.00"},{"action":"price","actor":"customer","do":"callAction","from":"admin","input":{"attribute":"data-price-input","contains":"Gaming Mouse","testid":"admin-item-row"},"namedAction":{"args":[0,1],"id":"price","params":[{"in":"body","name":"itemId","wireType":"u64"},{"in":"body","name":"price"}],"path":"/api/admin/price","reducer":"admin_change_price"},"settleMs":2000},{"actor":"customer","do":"expectActionOutcome","outcome":"refused","routeProvenBy":"admin"},{"actor":"admin","do":"reload","settleMs":2000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"admin-link","within":1000},{"actor":"customer","do":"reload","settleMs":2000},{"actor":"customer","do":"ensureSignedIn","name":"not-operator","readyTestid":"current-user"},{"actor":"customer","do":"expectNumber","equals":77,"in":{"contains":"Gaming Mouse","testid":"item-card"},"testid":"item-price","within":10000}]}],"id":201,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"customer","do":"signUp","name":"not-operator"},{"actor":"admin","do":"click","testid":"admin-link"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.progression.operations-access-specifications","requiresFeatures":["ecommerce.l2.price-history-features"],"role":"guarantee","source":"scenarios/02-strengthened.json","stablePackId":"ecommerce.operations-access"},{"checkGroupId":"stock-conservation","feature":{"actors":["admin","customer"],"criteria":[{"id":"202a","steps":[{"as":"product-East","do":"dbRecordStock","item":"Espresso Machine","warehouse":"East"},{"as":"product-West","do":"dbRecordStock","item":"Espresso Machine","warehouse":"West"},{"actor":"customer","as":"conservation-item-before","do":"recordNumber","in":{"contains":"Espresso Machine","testid":"item-card"},"testid":"item-stock"},{"actor":"admin","contains":"East","count":1,"do":"expect","testid":"admin-warehouse-item"},{"actor":"admin","as":"conservation-east-before","do":"recordNumber","in":{"contains":"East","testid":"admin-warehouse-item"},"testid":"warehouse-total"},{"actor":"admin","contains":"West","count":1,"do":"expect","testid":"admin-warehouse-item"},{"actor":"admin","as":"conservation-west-before","do":"recordNumber","in":{"contains":"West","testid":"admin-warehouse-item"},"testid":"warehouse-total"},{"actor":"admin","do":"fill","in":{"contains":"Espresso Machine","testid":"admin-item-row"},"testid":"transfer-from","text":"East"},{"actor":"admin","do":"fill","in":{"contains":"Espresso Machine","testid":"admin-item-row"},"testid":"transfer-to","text":"West"},{"actor":"admin","do":"fill","in":{"contains":"Espresso Machine","testid":"admin-item-row"},"testid":"transfer-qty","text":"17"},{"actor":"admin","do":"click","in":{"contains":"Espresso Machine","testid":"admin-item-row"},"testid":"transfer-submit"},{"actor":"admin","contains":"East","count":1,"do":"expect","testid":"admin-warehouse-item"},{"do":"dbExpectStock","item":"Espresso Machine","plus":-17,"relativeTo":"product-East","warehouse":"East","within":10000},{"do":"dbExpectStock","item":"Espresso Machine","plus":17,"relativeTo":"product-West","warehouse":"West","within":10000},{"actor":"admin","do":"reload","settleMs":1000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","testid":"admin-link","unlessVisible":"admin-revenue"},{"actor":"admin","do":"expectNumber","in":{"contains":"East","testid":"admin-warehouse-item"},"plus":-17,"relativeTo":"conservation-east-before","testid":"warehouse-total","within":10000},{"actor":"admin","contains":"West","count":1,"do":"expect","testid":"admin-warehouse-item"},{"actor":"admin","do":"expectNumber","in":{"contains":"West","testid":"admin-warehouse-item"},"plus":17,"relativeTo":"conservation-west-before","testid":"warehouse-total","within":10000},{"actor":"customer","do":"expectNumber","in":{"contains":"Espresso Machine","testid":"item-card"},"plus":0,"relativeTo":"conservation-item-before","testid":"item-stock","within":10000}]}],"id":202,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"customer","do":"signUp","name":"directional-stock"},{"actor":"admin","do":"click","testid":"admin-link"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.progression.inventory-conservation-specifications","requiresFeatures":["ecommerce.l2.stock-transfers-features"],"role":"guarantee","source":"scenarios/02-strengthened.json","stablePackId":"ecommerce.inventory-operations"}],"id":"selected-source-047","scenario":{"level":2,"writeUrlPattern":null},"source":"scenarios/02-strengthened.json"},{"checkGroups":[{"checkGroupId":"stock-transfer-overdraw","feature":{"actors":["admin","visitor"],"criteria":[{"id":"2c","steps":[{"as":"product-East","do":"dbRecordStock","item":"Headphones","warehouse":"East"},{"as":"product-West","do":"dbRecordStock","item":"Headphones","warehouse":"West"},{"actor":"visitor","as":"overdraw-item-before","do":"recordNumber","in":{"contains":"Headphones","testid":"item-card"},"testid":"item-stock"},{"actor":"admin","as":"overdraw-east-before","do":"recordNumber","in":{"contains":"East","testid":"admin-warehouse-item"},"testid":"warehouse-total"},{"actor":"admin","as":"overdraw-west-before","do":"recordNumber","in":{"contains":"West","testid":"admin-warehouse-item"},"testid":"warehouse-total"},{"actor":"admin","do":"fill","in":{"contains":"Headphones","testid":"admin-item-row"},"testid":"transfer-from","text":"East"},{"actor":"admin","do":"fill","in":{"contains":"Headphones","testid":"admin-item-row"},"testid":"transfer-to","text":"West"},{"actor":"admin","do":"fill","in":{"contains":"Headphones","testid":"admin-item-row"},"testid":"transfer-qty","text":"99999"},{"actor":"admin","do":"click","in":{"contains":"Headphones","testid":"admin-item-row"},"testid":"transfer-submit"},{"actor":"admin","do":"expect","testid":"order-error","within":6000},{"do":"dbExpectStock","item":"Headphones","plus":0,"relativeTo":"product-East","warehouse":"East"},{"do":"dbExpectStock","item":"Headphones","plus":0,"relativeTo":"product-West","warehouse":"West"},{"actor":"admin","do":"expectNumber","in":{"contains":"East","testid":"admin-warehouse-item"},"plus":0,"relativeTo":"overdraw-east-before","testid":"warehouse-total"},{"actor":"admin","do":"expectNumber","in":{"contains":"West","testid":"admin-warehouse-item"},"plus":0,"relativeTo":"overdraw-west-before","testid":"warehouse-total"},{"actor":"visitor","do":"expectNumber","in":{"contains":"Headphones","testid":"item-card"},"plus":0,"relativeTo":"overdraw-item-before","testid":"item-stock"}]}],"id":2,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"click","testid":"admin-link"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.transactional-integrity","requiresFeatures":["ecommerce.l2.stock-transfers-features"],"role":"guarantee","source":"scenarios/02-transfer-overdraw.json"}],"id":"selected-source-048","scenario":{"level":2,"writeUrlPattern":null},"source":"scenarios/02-transfer-overdraw.json"},{"checkGroups":[{"checkGroupId":"stock-transfers","feature":{"actors":["admin"],"criteria":[{"id":"2b","steps":[{"as":"product-East","do":"dbRecordStock","item":"Headphones","warehouse":"East"},{"as":"product-West","do":"dbRecordStock","item":"Headphones","warehouse":"West"},{"actor":"admin","contains":"East","count":1,"do":"expect","testid":"admin-warehouse-item"},{"actor":"admin","as":"warehouse-east-before","do":"recordNumber","in":{"contains":"East","testid":"admin-warehouse-item"},"testid":"warehouse-total"},{"actor":"admin","contains":"West","count":1,"do":"expect","testid":"admin-warehouse-item"},{"actor":"admin","as":"warehouse-west-before","do":"recordNumber","in":{"contains":"West","testid":"admin-warehouse-item"},"testid":"warehouse-total"},{"actor":"admin","do":"fill","in":{"contains":"Headphones","testid":"admin-item-row"},"testid":"transfer-from","text":"East"},{"actor":"admin","do":"fill","in":{"contains":"Headphones","testid":"admin-item-row"},"testid":"transfer-to","text":"West"},{"actor":"admin","do":"fill","in":{"contains":"Headphones","testid":"admin-item-row"},"testid":"transfer-qty","text":"10"},{"actor":"admin","do":"click","in":{"contains":"Headphones","testid":"admin-item-row"},"testid":"transfer-submit"},{"actor":"admin","contains":"East","count":1,"do":"expect","testid":"admin-warehouse-item"},{"actor":"admin","do":"expectNumber","in":{"contains":"East","testid":"admin-warehouse-item"},"plus":-10,"relativeTo":"warehouse-east-before","testid":"warehouse-total","within":10000},{"actor":"admin","contains":"West","count":1,"do":"expect","testid":"admin-warehouse-item"},{"actor":"admin","do":"expectNumber","in":{"contains":"West","testid":"admin-warehouse-item"},"plus":10,"relativeTo":"warehouse-west-before","testid":"warehouse-total","within":10000},{"do":"dbExpectStock","item":"Headphones","plus":-10,"relativeTo":"product-East","warehouse":"East","within":10000},{"do":"dbExpectStock","item":"Headphones","plus":10,"relativeTo":"product-West","warehouse":"West","within":10000}]}],"id":2,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"click","testid":"admin-link"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.live-state","requiresFeatures":["ecommerce.l2.stock-transfers-features"],"role":"guarantee","source":"scenarios/02-transfer-totals.json"}],"id":"selected-source-049","scenario":{"level":2,"writeUrlPattern":null},"source":"scenarios/02-transfer-totals.json"},{"checkGroups":[{"checkGroupId":"cart-expiration","feature":{"actors":["customer","watcher"],"criteria":[{"id":"304a","steps":[{"actor":"watcher","do":"wait","ms":310000},{"actor":"watcher","do":"reload","settleMs":1000},{"actor":"watcher","do":"expectNumber","in":{"contains":"Air Purifier","testid":"item-card"},"plus":0,"relativeTo":"before","testid":"item-stock","within":30000},{"actor":"customer","do":"openClient","settleMs":3000},{"actor":"customer","do":"expect","testid":"cart-expired-notice","within":10000},{"actor":"customer","do":"expectNumber","equals":0,"testid":"cart-count"}]}],"id":304,"setup":[{"actor":"customer","do":"signUp","name":"cart-expiry"},{"actor":"watcher","as":"before","do":"recordNumber","in":{"contains":"Air Purifier","testid":"item-card"},"testid":"item-stock"},{"actor":"customer","do":"click","in":{"contains":"Air Purifier","testid":"item-card"},"testid":"add-to-cart"},{"actor":"watcher","do":"reload","settleMs":1000},{"actor":"watcher","do":"expectNumber","in":{"contains":"Air Purifier","testid":"item-card"},"plus":-1,"relativeTo":"before","testid":"item-stock","within":10000},{"actor":"customer","do":"closeClient"}]},"packId":"ecommerce.l3.cart-expiration-features","role":"feature","source":"scenarios/03-cart-expiration.json","stablePackId":"ecommerce.l3.cart-expiration"}],"id":"selected-source-050","scenario":{"level":3,"writeUrlPattern":null},"source":"scenarios/03-cart-expiration.json"},{"checkGroups":[{"checkGroupId":"scheduled-work-access","feature":{"actors":["admin","customer"],"criteria":[{"id":"317a","steps":[{"actor":"admin","do":"fill","testid":"schedule-restock-item","text":"Webcam"},{"actor":"admin","do":"fill","testid":"schedule-restock-warehouse","text":"West"},{"actor":"admin","do":"fill","testid":"schedule-restock-qty","text":"3"},{"actor":"admin","do":"fill","testid":"schedule-restock-delay","text":"180"},{"action":"scheduleRestock","actor":"customer","authentication":"actor","do":"callAction","from":"admin","input":{"attribute":"data-action-input","testid":"schedule-restock-submit"},"namedAction":{"args":["","",0,0],"id":"scheduleRestock","method":"POST","params":[{"in":"body","name":"item"},{"in":"body","name":"warehouse"},{"in":"body","name":"quantity"},{"in":"body","name":"delaySeconds"}],"path":"/api/admin/scheduled-restocks","reducer":"schedule_restock"},"settleMs":2000},{"actor":"customer","do":"expectActionOutcome","outcome":"refused"},{"actor":"customer","do":"replayAs","from":"admin","match":"DELETE","namedAction":{"args":[0],"id":"cancelScheduledRestock","method":"DELETE","params":[{"in":"path","name":"restockId","placeholder":"{restockId}","wireType":"u64"}],"path":"/api/admin/scheduled-restocks/{restockId}","reducer":"cancel_scheduled_restock"},"namedTarget":{"attribute":"data-entity-id","testid":"pending-restock-item","valueType":"string"},"settleMs":2000},{"actor":"customer","do":"expectReplayRejected"},{"actor":"admin","count":1,"do":"expect","testid":"pending-restock-item"},{"actor":"admin","do":"click","in":{"testid":"pending-restock-item"},"testid":"pending-restock-cancel"}]}],"id":317,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"click","testid":"admin-link"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"restocks-link"},{"actor":"customer","do":"signUp","name":"restock-outsider"},{"actor":"admin","do":"fill","testid":"schedule-restock-item","text":"Webcam"},{"actor":"admin","do":"fill","testid":"schedule-restock-warehouse","text":"West"},{"actor":"admin","do":"fill","testid":"schedule-restock-qty","text":"3"},{"actor":"admin","do":"fill","testid":"schedule-restock-delay","text":"180"},{"actor":"admin","do":"click","testid":"schedule-restock-submit"},{"actor":"admin","count":1,"do":"expect","testid":"pending-restock-item"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.l3.deferred-access-specifications","requiresFeatures":["ecommerce.l3.scheduled-restocks-features"],"role":"guarantee","source":"scenarios/03-deferred-access.json","stablePackId":"ecommerce.l3.deferred-access"}],"id":"selected-source-051","scenario":{"level":3,"writeUrlPattern":null},"source":"scenarios/03-deferred-access.json"},{"checkGroups":[{"checkGroupId":"restart-survival","feature":{"actors":["admin"],"criteria":[{"id":"311a","steps":[{"do":"dbExpectStock","item":"Air Purifier","plus":5,"relativeTo":"before","within":70000},{"actor":"admin","do":"reload","settleMs":2000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"admin-link"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"restocks-link"},{"actor":"admin","do":"expect","testid":"schedule-restock-submit"},{"absent":true,"actor":"admin","do":"expect","testid":"pending-restock-item"}]}],"id":311,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"click","testid":"admin-link"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"restocks-link"},{"as":"ordinaryBefore","do":"dbRecordStock","item":"Air Purifier"},{"actor":"admin","do":"fill","testid":"schedule-restock-item","text":"Air Purifier"},{"actor":"admin","do":"fill","testid":"schedule-restock-warehouse","text":"East"},{"actor":"admin","do":"fill","testid":"schedule-restock-qty","text":"5"},{"actor":"admin","do":"fill","testid":"schedule-restock-delay","text":"45"},{"actor":"admin","do":"click","testid":"schedule-restock-submit"},{"actor":"admin","count":1,"do":"expect","testid":"pending-restock-item","within":10000},{"do":"dbExpectStock","item":"Air Purifier","plus":5,"relativeTo":"ordinaryBefore","within":70000},{"actor":"admin","do":"reload","settleMs":1000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","testid":"admin-link"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"restocks-link"},{"actor":"admin","do":"expect","testid":"schedule-restock-submit"},{"absent":true,"actor":"admin","do":"expect","testid":"pending-restock-item"},{"as":"before","do":"dbRecordStock","item":"Air Purifier"},{"actor":"admin","do":"fill","testid":"schedule-restock-item","text":"Air Purifier"},{"actor":"admin","do":"fill","testid":"schedule-restock-warehouse","text":"East"},{"actor":"admin","do":"fill","testid":"schedule-restock-qty","text":"5"},{"actor":"admin","do":"fill","testid":"schedule-restock-delay","text":"45"},{"actor":"admin","do":"click","testid":"schedule-restock-submit"},{"actor":"admin","count":1,"do":"expect","testid":"pending-restock-item","within":10000},{"do":"dbExpectStock","item":"Air Purifier","plus":0,"relativeTo":"before"},{"do":"restartBackend","settleMs":15000}]},"observations":["requested","unmentioned"],"packId":"ecommerce.l3.deferred-durability-specifications","requiresFeatures":["ecommerce.l3.scheduled-restocks-features"],"role":"guarantee","source":"scenarios/03-deferred-durability.json","stablePackId":"ecommerce.l3.deferred-durability"},{"checkGroupId":"restart-survival","feature":{"actors":["customer","watcher"],"criteria":[{"id":"314a","steps":[{"atMost":70000,"do":"expectElapsed","since":"pending-314"},{"actor":"watcher","do":"reload","settleMs":1000},{"atMost":70000,"do":"expectElapsed","since":"pending-314"},{"actor":"watcher","do":"expectNumber","in":{"contains":"Desk Lamp","testid":"item-card"},"plus":-1,"relativeTo":"before","testid":"item-stock","within":1000},{"atMost":70000,"do":"expectElapsed","since":"pending-314"},{"actor":"customer","do":"wait","ms":110000,"since":"pending-314-accepted"},{"actor":"watcher","do":"reload","settleMs":2000},{"actor":"watcher","do":"expectNumber","in":{"contains":"Desk Lamp","testid":"item-card"},"plus":0,"relativeTo":"before","testid":"item-stock","within":10000},{"actor":"customer","do":"reload","settleMs":1000},{"actor":"customer","do":"ensureSignedIn","name":"durable-reservation","readyTestid":"current-user"},{"actor":"customer","do":"click","testid":"cart-toggle","unlessVisible":"cart-item"},{"actor":"customer","do":"expect","in":{"contains":"Desk Lamp","testid":"cart-item"},"testid":"cart-item-expired","within":10000}]}],"id":314,"setup":[{"actor":"customer","do":"signUp","name":"durable-reservation"},{"actor":"watcher","as":"before","do":"recordNumber","in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"item-stock"},{"as":"pending-314","do":"recordTime"},{"actor":"customer","do":"click","in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"add-to-cart"},{"actor":"watcher","do":"reload","settleMs":1000},{"actor":"watcher","do":"expectNumber","in":{"contains":"Desk Lamp","testid":"item-card"},"plus":-1,"relativeTo":"before","testid":"item-stock","within":10000},{"as":"pending-314-accepted","do":"recordTime"},{"actor":"customer","do":"wait","ms":30000},{"do":"restartBackend","settleMs":15000},{"actor":"watcher","do":"reload","settleMs":3000}]},"observations":["requested","unmentioned"],"packId":"ecommerce.l3.deferred-durability-specifications","requiresFeatures":["ecommerce.l3.reservations-features"],"role":"guarantee","source":"scenarios/03-deferred-durability.json","stablePackId":"ecommerce.l3.deferred-durability"},{"checkGroupId":"restart-survival","feature":{"actors":["customer","staff"],"criteria":[{"id":"315a","steps":[{"actor":"customer","do":"wait","ms":75000,"since":"delivery-start-accepted"},{"actor":"customer","do":"reload","settleMs":1000},{"actor":"customer","do":"ensureSignedIn","name":"durable-delivery","readyTestid":"current-user"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"customer","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"customer","do":"expect","ignoreCase":true,"in":{"contains":"Keyboard","testid":"order-item"},"testid":"order-status","value":"delivered","within":10000}]}],"id":315,"setup":[{"actor":"customer","do":"signUp","name":"durable-delivery"},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"staff","do":"click","testid":"staff-link"},{"actor":"customer","do":"click","in":{"contains":"Keyboard","testid":"item-card"},"testid":"buy-now"},{"actor":"staff","do":"reload","settleMs":1000},{"actor":"staff","do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026","readyTestid":"current-user"},{"actor":"staff","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"staff","do":"click","testid":"staff-link","unlessVisible":"queue-item"},{"actor":"staff","contains":"Keyboard","do":"expect","testid":"queue-item","within":10000},{"actor":"staff","do":"click","in":{"contains":"Keyboard","testid":"queue-item"},"testid":"ship-submit"},{"actor":"customer","do":"reload","settleMs":1000},{"actor":"customer","do":"ensureSignedIn","name":"durable-delivery","readyTestid":"current-user"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"customer","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"customer","do":"expect","ignoreCase":true,"in":{"contains":"Keyboard","testid":"order-item"},"testid":"order-status","value":"shipped","within":10000},{"as":"delivery-start-accepted","do":"recordTime"},{"actor":"customer","do":"wait","ms":20000},{"do":"restartBackend","settleMs":15000},{"actor":"customer","do":"reload","settleMs":3000},{"actor":"customer","do":"ensureSignedIn","name":"durable-delivery","readyTestid":"current-user"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"customer","do":"click","testid":"orders-toggle"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.l3.deferred-durability-specifications","requiresFeatures":["ecommerce.l3.order-delivery-features"],"role":"guarantee","source":"scenarios/03-deferred-durability.json","stablePackId":"ecommerce.l3.deferred-durability"},{"checkGroupId":"restart-survival","feature":{"actors":["customer","watcher"],"criteria":[{"id":"316a","steps":[{"atMost":250000,"do":"expectElapsed","since":"pending-316"},{"actor":"customer","do":"reload","settleMs":1000},{"actor":"customer","do":"ensureSignedIn","name":"durable-cart","readyTestid":"current-user"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"customer","do":"click","testid":"cart-toggle","unlessVisible":"cart-item"},{"atMost":250000,"do":"expectElapsed","since":"pending-316"},{"actor":"customer","do":"expectNumber","equals":1,"testid":"cart-count","within":1000},{"atMost":250000,"do":"expectElapsed","since":"pending-316"},{"actor":"customer","do":"wait","ms":310000,"since":"pending-316-accepted"},{"actor":"customer","do":"reload","settleMs":3000},{"actor":"customer","do":"ensureSignedIn","name":"durable-cart","readyTestid":"current-user"},{"actor":"customer","do":"click","testid":"cart-toggle"},{"actor":"customer","do":"expectNumber","equals":0,"testid":"cart-count","within":10000},{"actor":"customer","do":"expect","testid":"cart-expired-notice","within":10000},{"actor":"watcher","do":"reload","settleMs":1000},{"actor":"watcher","do":"expectNumber","in":{"contains":"Bluetooth Speaker","testid":"item-card"},"plus":0,"relativeTo":"before","testid":"item-stock","within":10000}]}],"id":316,"setup":[{"actor":"customer","do":"signUp","name":"durable-cart"},{"actor":"watcher","as":"before","do":"recordNumber","in":{"contains":"Bluetooth Speaker","testid":"item-card"},"testid":"item-stock"},{"as":"pending-316","do":"recordTime"},{"actor":"customer","do":"click","in":{"contains":"Bluetooth Speaker","testid":"item-card"},"testid":"add-to-cart"},{"actor":"watcher","do":"reload","settleMs":1000},{"actor":"watcher","do":"expectNumber","in":{"contains":"Bluetooth Speaker","testid":"item-card"},"plus":-1,"relativeTo":"before","testid":"item-stock","within":10000},{"as":"pending-316-accepted","do":"recordTime"},{"actor":"customer","do":"wait","ms":120000},{"do":"restartBackend","settleMs":15000},{"actor":"watcher","do":"reload","settleMs":3000}]},"observations":["requested","unmentioned"],"packId":"ecommerce.l3.deferred-durability-specifications","requiresFeatures":["ecommerce.l3.cart-expiration-features"],"role":"guarantee","source":"scenarios/03-deferred-durability.json","stablePackId":"ecommerce.l3.deferred-durability"}],"id":"selected-source-052","scenario":{"level":3,"writeUrlPattern":null},"source":"scenarios/03-deferred-durability.json"},{"checkGroups":[{"checkGroupId":"exactly-once","feature":{"actors":["admin","watcher"],"criteria":[{"id":"311a","steps":[{"actor":"watcher","do":"reload","settleMs":2000},{"do":"dbExpectStock","item":"Air Purifier","plus":5,"relativeTo":"before","within":45000},{"do":"restartBackend","settleMs":15000},{"actor":"watcher","do":"reload","settleMs":3000},{"actor":"watcher","do":"wait","ms":15000},{"do":"dbExpectStock","item":"Air Purifier","plus":5,"relativeTo":"before"}]}],"id":311,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"click","testid":"admin-link"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"restocks-link"},{"as":"before","do":"dbRecordStock","item":"Air Purifier"},{"actor":"admin","do":"fill","testid":"schedule-restock-item","text":"Air Purifier"},{"actor":"admin","do":"fill","testid":"schedule-restock-warehouse","text":"East"},{"actor":"admin","do":"fill","testid":"schedule-restock-qty","text":"5"},{"actor":"admin","do":"fill","testid":"schedule-restock-delay","text":"20"},{"actor":"admin","do":"click","testid":"schedule-restock-submit"},{"actor":"admin","count":1,"do":"expect","testid":"pending-restock-item","within":10000},{"do":"dbExpectStock","item":"Air Purifier","plus":0,"relativeTo":"before"},{"do":"restartBackend","settleMs":15000},{"actor":"watcher","do":"reload","settleMs":3000}]},"observations":["requested","unmentioned"],"packId":"ecommerce.l3.deferred-integrity-specifications","requiresFeatures":["ecommerce.l3.scheduled-restocks-features"],"role":"guarantee","source":"scenarios/03-deferred-integrity.json","stablePackId":"ecommerce.l3.deferred-integrity"},{"checkGroupId":"exactly-once","feature":{"actors":["customer","staff"],"criteria":[{"id":"312a","steps":[{"actor":"staff","do":"reload","settleMs":2000},{"actor":"staff","do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026","readyTestid":"current-user"},{"actor":"staff","do":"click","ifAvailable":true,"testid":"staff-link"},{"actor":"staff","contains":"Desk Lamp","count":1,"do":"expect","testid":"completed-order-item"},{"actor":"staff","do":"expect","ignoreCase":true,"in":{"contains":"Desk Lamp","testid":"completed-order-item"},"testid":"completed-order-status","value":"delivered"}]}],"id":312,"setup":[{"actor":"customer","do":"signUp","name":"once-delivery"},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"staff","do":"click","testid":"staff-link"},{"actor":"customer","do":"click","in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"buy-now"},{"actor":"staff","do":"reload","settleMs":1000},{"actor":"staff","do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026","readyTestid":"current-user"},{"actor":"staff","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"staff","do":"click","testid":"staff-link","unlessVisible":"queue-item"},{"actor":"staff","contains":"Desk Lamp","do":"expect","testid":"queue-item","within":10000},{"actor":"staff","do":"click","in":{"contains":"Desk Lamp","testid":"queue-item"},"testid":"ship-submit"},{"actor":"customer","do":"reload","settleMs":1000},{"actor":"customer","do":"ensureSignedIn","name":"once-delivery","readyTestid":"current-user"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"customer","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"customer","do":"expect","ignoreCase":true,"in":{"contains":"Desk Lamp","testid":"order-item"},"testid":"order-status","value":"shipped","within":10000},{"actor":"customer","do":"wait","ms":70000},{"actor":"customer","do":"reload","settleMs":1000},{"actor":"customer","do":"ensureSignedIn","name":"once-delivery","readyTestid":"current-user"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"customer","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"customer","do":"expect","ignoreCase":true,"in":{"contains":"Desk Lamp","testid":"order-item"},"testid":"order-status","value":"delivered","within":15000},{"do":"restartBackend","settleMs":15000},{"actor":"staff","do":"reload","settleMs":3000},{"actor":"staff","do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026","readyTestid":"current-user"},{"actor":"staff","do":"click","ifAvailable":true,"testid":"staff-link","within":1000}]},"observations":["requested","unmentioned"],"packId":"ecommerce.l3.deferred-integrity-specifications","requiresFeatures":["ecommerce.l3.order-delivery-features"],"role":"guarantee","source":"scenarios/03-deferred-integrity.json","stablePackId":"ecommerce.l3.deferred-integrity"},{"checkGroupId":"stock-conservation","feature":{"actors":["customer","watcher"],"criteria":[{"id":"313a","steps":[{"actor":"watcher","do":"wait","ms":100000},{"actor":"watcher","do":"reload","settleMs":1000},{"actor":"watcher","do":"expectNumber","in":{"contains":"Keyboard","testid":"item-card"},"plus":0,"relativeTo":"before","testid":"item-stock","within":30000}]}],"id":313,"setup":[{"actor":"customer","do":"signUp","name":"conserve-expiry"},{"actor":"watcher","as":"before","do":"recordNumber","in":{"contains":"Keyboard","testid":"item-card"},"testid":"item-stock"},{"actor":"customer","do":"click","in":{"contains":"Keyboard","testid":"item-card"},"testid":"add-to-cart"},{"actor":"watcher","do":"reload","settleMs":1000},{"actor":"watcher","do":"expectNumber","in":{"contains":"Keyboard","testid":"item-card"},"plus":-1,"relativeTo":"before","testid":"item-stock","within":10000}]},"observations":["requested","unmentioned"],"packId":"ecommerce.l3.deferred-integrity-specifications","requiresFeatures":["ecommerce.l3.reservations-features"],"role":"guarantee","source":"scenarios/03-deferred-integrity.json","stablePackId":"ecommerce.l3.deferred-integrity"},{"checkGroupId":"stock-conservation","feature":{"actors":["customer","watcher"],"criteria":[{"id":"314a","steps":[{"actor":"customer","do":"click","testid":"checkout-submit"},{"actor":"customer","do":"expectNumber","equals":0,"testid":"cart-count","within":10000},{"actor":"customer","do":"reload","settleMs":1000},{"actor":"customer","do":"ensureSignedIn","name":"conserve-checkout","readyTestid":"current-user"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"customer","do":"click","testid":"orders-toggle"},{"actor":"customer","contains":"Headphones","do":"expectElementCount","equals":1,"testid":"order-item","within":10000},{"actor":"watcher","do":"reload","settleMs":1000},{"actor":"watcher","do":"expectNumber","in":{"contains":"Headphones","testid":"item-card"},"plus":-1,"relativeTo":"before","testid":"item-stock","within":10000}]}],"id":314,"setup":[{"actor":"customer","do":"signUp","name":"conserve-checkout"},{"actor":"watcher","as":"before","do":"recordNumber","in":{"contains":"Headphones","testid":"item-card"},"testid":"item-stock"},{"actor":"customer","do":"click","in":{"contains":"Headphones","testid":"item-card"},"testid":"add-to-cart"},{"actor":"customer","do":"click","testid":"cart-toggle"},{"actor":"watcher","do":"reload","settleMs":1000},{"actor":"watcher","do":"expectNumber","in":{"contains":"Headphones","testid":"item-card"},"plus":-1,"relativeTo":"before","testid":"item-stock","within":10000}]},"observations":["requested","unmentioned"],"packId":"ecommerce.l3.deferred-integrity-specifications","requiresFeatures":["ecommerce.l3.reservations-features"],"role":"guarantee","source":"scenarios/03-deferred-integrity.json","stablePackId":"ecommerce.l3.deferred-integrity"}],"id":"selected-source-053","scenario":{"level":3,"writeUrlPattern":null},"source":"scenarios/03-deferred-integrity.json"},{"checkGroups":[{"checkGroupId":"order-delivery","feature":{"actors":["customer","staff"],"criteria":[{"id":"303a","steps":[{"actor":"customer","do":"wait","ms":70000},{"actor":"customer","do":"reload","settleMs":1000},{"actor":"customer","do":"ensureSignedIn","name":"delivery-live","readyTestid":"current-user"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"customer","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"customer","do":"expect","ignoreCase":true,"in":{"contains":"Gaming Mouse","testid":"order-item"},"testid":"order-status","value":"delivered","within":15000},{"actor":"staff","do":"reload","settleMs":1000},{"actor":"staff","do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026","readyTestid":"current-user"},{"actor":"staff","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"staff","do":"click","testid":"staff-link","unlessVisible":"completed-order-item"},{"actor":"staff","do":"expect","ignoreCase":true,"in":{"contains":"Gaming Mouse","testid":"completed-order-item"},"testid":"completed-order-status","value":"delivered","within":15000}]}],"id":303,"setup":[{"actor":"customer","do":"signUp","name":"delivery-live"},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"staff","do":"click","testid":"staff-link"},{"actor":"customer","do":"click","in":{"contains":"Gaming Mouse","testid":"item-card"},"testid":"buy-now"},{"actor":"staff","do":"reload","settleMs":1000},{"actor":"staff","do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026","readyTestid":"current-user"},{"actor":"staff","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"staff","do":"click","testid":"staff-link","unlessVisible":"queue-item"},{"actor":"staff","contains":"Gaming Mouse","do":"expect","testid":"queue-item","within":10000},{"actor":"staff","do":"click","in":{"contains":"Gaming Mouse","testid":"queue-item"},"testid":"ship-submit"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"customer","do":"reload","settleMs":1000},{"actor":"customer","do":"ensureSignedIn","name":"delivery-live","readyTestid":"current-user"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"customer","do":"click","testid":"orders-toggle"},{"actor":"customer","do":"expect","ignoreCase":true,"in":{"contains":"Gaming Mouse","testid":"order-item"},"testid":"order-status","value":"shipped","within":10000}]},"packId":"ecommerce.l3.order-delivery-features","role":"feature","source":"scenarios/03-order-delivery.json","stablePackId":"ecommerce.l3.order-delivery"},{"checkGroupId":"order-delivery","feature":{"actors":["customer"],"criteria":[{"id":"305a","steps":[{"actor":"customer","do":"wait","ms":70000},{"actor":"customer","do":"reload","settleMs":1000},{"actor":"customer","do":"ensureSignedIn","name":"delivery-cancel","readyTestid":"current-user"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"customer","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"customer","do":"expect","ignoreCase":true,"in":{"contains":"Keyboard","testid":"order-item"},"testid":"order-status","value":"cancelled"}]}],"id":305,"setup":[{"actor":"customer","do":"signUp","name":"delivery-cancel"},{"actor":"customer","do":"click","in":{"contains":"Keyboard","testid":"item-card"},"testid":"buy-now"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"customer","do":"click","testid":"orders-toggle"},{"actor":"customer","do":"click","in":{"contains":"Keyboard","testid":"order-item"},"testid":"cancel-order"},{"actor":"customer","do":"expect","ignoreCase":true,"in":{"contains":"Keyboard","testid":"order-item"},"testid":"order-status","value":"cancelled","within":10000}]},"packId":"ecommerce.l3.order-delivery-features","role":"feature","source":"scenarios/03-order-delivery.json","stablePackId":"ecommerce.l3.order-delivery"}],"id":"selected-source-054","scenario":{"level":3,"writeUrlPattern":null},"source":"scenarios/03-order-delivery.json"},{"checkGroups":[{"checkGroupId":"reservations","feature":{"actors":["shopper","watcher"],"criteria":[{"id":"301a","steps":[{"actor":"shopper","do":"click","in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"add-to-cart"},{"actor":"watcher","do":"expectNumber","in":{"contains":"Desk Lamp","testid":"item-card"},"plus":-1,"relativeTo":"before","testid":"item-stock","within":10000}]}],"id":301,"setup":[{"actor":"shopper","do":"signUp","name":"reserve-stock"},{"actor":"watcher","as":"before","do":"recordNumber","in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"item-stock"}]},"packId":"ecommerce.l3.reservations-features","role":"feature","source":"scenarios/03-reservations.json","stablePackId":"ecommerce.l3.reservations"},{"checkGroupId":"reservations","feature":{"actors":["shopper"],"criteria":[{"id":"305a","steps":[{"actor":"shopper","atLeast":1,"atMost":90,"do":"expectNumber","in":{"contains":"Gaming Mouse","testid":"cart-item"},"testid":"cart-reservation-timer"},{"actor":"shopper","as":"initial-countdown","do":"recordNumber","in":{"contains":"Gaming Mouse","testid":"cart-item"},"testid":"cart-reservation-timer"},{"actor":"shopper","do":"wait","ms":1000},{"actor":"shopper","comparison":"atMost","do":"expectNumber","in":{"contains":"Gaming Mouse","testid":"cart-item"},"plus":-1,"relativeTo":"initial-countdown","testid":"cart-reservation-timer","within":10000}]}],"id":305,"setup":[{"actor":"shopper","do":"signUp","name":"reserve-clock"},{"actor":"shopper","do":"click","in":{"contains":"Gaming Mouse","testid":"item-card"},"testid":"add-to-cart"},{"actor":"shopper","do":"click","testid":"cart-toggle"}]},"packId":"ecommerce.l3.reservations-features","role":"feature","source":"scenarios/03-reservations.json","stablePackId":"ecommerce.l3.reservations"},{"checkGroupId":"reservations","feature":{"actors":["shopper"],"criteria":[{"id":"306a","steps":[{"actor":"shopper","do":"click","testid":"checkout-submit"},{"actor":"shopper","do":"expectNumber","equals":0,"testid":"cart-count","within":10000},{"actor":"shopper","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"shopper","do":"click","testid":"orders-toggle"},{"actor":"shopper","contains":"Keyboard","count":1,"do":"expect","testid":"order-item"}]}],"id":306,"setup":[{"actor":"shopper","do":"signUp","name":"reserve-checkout"},{"actor":"shopper","do":"click","in":{"contains":"Keyboard","testid":"item-card"},"testid":"add-to-cart"},{"actor":"shopper","do":"click","testid":"cart-toggle"}]},"packId":"ecommerce.l3.reservations-features","role":"feature","source":"scenarios/03-reservations.json","stablePackId":"ecommerce.l3.reservations"},{"checkGroupId":"reservations","feature":{"actors":["shopper"],"criteria":[{"id":"307a","steps":[{"actor":"shopper","do":"wait","ms":100000},{"actor":"shopper","do":"expect","in":{"contains":"Bluetooth Speaker","testid":"cart-item"},"testid":"cart-item-expired","within":15000}]}],"id":307,"setup":[{"actor":"shopper","do":"signUp","name":"reserve-expiry"},{"actor":"shopper","do":"click","in":{"contains":"Bluetooth Speaker","testid":"item-card"},"testid":"add-to-cart"},{"actor":"shopper","do":"click","testid":"cart-toggle"}]},"packId":"ecommerce.l3.reservations-features","role":"feature","source":"scenarios/03-reservations.json","stablePackId":"ecommerce.l3.reservations"},{"checkGroupId":"reservations","feature":{"actors":["shopper"],"criteria":[{"id":"308a","steps":[{"actor":"shopper","do":"wait","ms":40000},{"actor":"shopper","atLeast":35,"do":"expectNumber","in":{"contains":"Headphones","testid":"cart-item"},"testid":"cart-reservation-timer"},{"absent":true,"actor":"shopper","do":"expect","in":{"contains":"Headphones","testid":"cart-item"},"testid":"cart-item-expired"}]}],"id":308,"setup":[{"actor":"shopper","do":"signUp","name":"reserve-renew"},{"actor":"shopper","do":"click","in":{"contains":"Headphones","testid":"item-card"},"testid":"add-to-cart"},{"actor":"shopper","do":"wait","ms":60000},{"actor":"shopper","do":"click","in":{"contains":"Headphones","testid":"item-card"},"testid":"add-to-cart"},{"actor":"shopper","do":"click","testid":"cart-toggle"}]},"packId":"ecommerce.l3.reservations-features","role":"feature","source":"scenarios/03-reservations.json","stablePackId":"ecommerce.l3.reservations"}],"id":"selected-source-055","scenario":{"level":3,"writeUrlPattern":null},"source":"scenarios/03-reservations.json"},{"checkGroups":[{"checkGroupId":"scheduled-restocks","feature":{"actors":["admin","watcher"],"criteria":[{"id":"305a","steps":[{"actor":"admin","as":"ledger-before","count":true,"do":"recordNumber","testid":"stock-ledger-entry"},{"actor":"admin","do":"fill","testid":"schedule-restock-item","text":"Keyboard"},{"actor":"admin","do":"fill","testid":"schedule-restock-warehouse","text":"West"},{"actor":"admin","do":"fill","testid":"schedule-restock-qty","text":"7"},{"actor":"admin","do":"fill","testid":"schedule-restock-delay","text":"15"},{"actor":"admin","do":"click","testid":"schedule-restock-submit"},{"actor":"admin","do":"wait","ms":25000},{"actor":"watcher","do":"reload","settleMs":2000},{"actor":"admin","do":"reload","settleMs":2000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"admin-link"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"restocks-link"},{"actor":"watcher","do":"expectNumber","in":{"contains":"Keyboard","testid":"item-card"},"plus":7,"relativeTo":"before","testid":"item-stock","within":15000},{"absent":true,"actor":"admin","do":"expect","testid":"pending-restock-item"},{"actor":"admin","do":"expectElementCount","plus":1,"relativeTo":"ledger-before","testid":"stock-ledger-entry"}]}],"id":305,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"click","testid":"admin-link"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"restocks-link"},{"actor":"watcher","as":"before","do":"recordNumber","in":{"contains":"Keyboard","testid":"item-card"},"testid":"item-stock"}]},"packId":"ecommerce.l3.scheduled-restocks-features","role":"feature","source":"scenarios/03-scheduled-restock-apply.json","stablePackId":"ecommerce.l3.scheduled-restocks"}],"id":"selected-source-056","scenario":{"level":3,"writeUrlPattern":null},"source":"scenarios/03-scheduled-restock-apply.json"},{"checkGroups":[{"checkGroupId":"scheduled-restocks","feature":{"actors":["admin","watcher"],"criteria":[{"id":"306a","steps":[{"actor":"admin","do":"fill","testid":"schedule-restock-item","text":"Desk Lamp"},{"actor":"admin","do":"fill","testid":"schedule-restock-warehouse","text":"East"},{"actor":"admin","do":"fill","testid":"schedule-restock-qty","text":"9"},{"actor":"admin","do":"fill","testid":"schedule-restock-delay","text":"15"},{"actor":"admin","do":"click","testid":"schedule-restock-submit"},{"actor":"admin","count":1,"do":"expect","testid":"pending-restock-item"},{"actor":"admin","do":"click","in":{"testid":"pending-restock-item"},"testid":"pending-restock-cancel"},{"actor":"admin","do":"wait","ms":25000},{"actor":"watcher","do":"reload","settleMs":2000},{"actor":"watcher","do":"expectNumber","in":{"contains":"Desk Lamp","testid":"item-card"},"plus":0,"relativeTo":"before","testid":"item-stock"}]}],"id":306,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"click","testid":"admin-link"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"restocks-link"},{"actor":"watcher","as":"before","do":"recordNumber","in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"item-stock"}]},"packId":"ecommerce.l3.scheduled-restocks-features","role":"feature","source":"scenarios/03-scheduled-restock-cancel.json","stablePackId":"ecommerce.l3.scheduled-restocks"}],"id":"selected-source-057","scenario":{"level":3,"writeUrlPattern":null},"source":"scenarios/03-scheduled-restock-cancel.json"},{"checkGroups":[{"checkGroupId":"scheduled-restocks","feature":{"actors":["admin"],"criteria":[{"id":"302a","steps":[{"actor":"admin","do":"fill","testid":"schedule-restock-item","text":"Webcam"},{"actor":"admin","do":"fill","testid":"schedule-restock-warehouse","text":"East"},{"actor":"admin","do":"fill","testid":"schedule-restock-qty","text":"7"},{"actor":"admin","do":"fill","testid":"schedule-restock-delay","text":"90"},{"actor":"admin","do":"click","testid":"schedule-restock-submit"},{"actor":"admin","count":1,"do":"expect","testid":"pending-restock-item","within":10000},{"actor":"admin","atLeast":1,"atMost":90,"do":"expectNumber","in":{"testid":"pending-restock-item"},"testid":"pending-restock-remaining"},{"actor":"admin","as":"initial-countdown","do":"recordNumber","in":{"testid":"pending-restock-item"},"testid":"pending-restock-remaining"},{"actor":"admin","do":"wait","ms":1000},{"actor":"admin","comparison":"atMost","do":"expectNumber","in":{"testid":"pending-restock-item"},"plus":-1,"relativeTo":"initial-countdown","testid":"pending-restock-remaining","within":10000},{"actor":"admin","do":"click","in":{"testid":"pending-restock-item"},"testid":"pending-restock-cancel"}]}],"id":302,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"click","testid":"admin-link"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"restocks-link"}]},"packId":"ecommerce.l3.scheduled-restocks-features","role":"feature","source":"scenarios/03-scheduled-restocks.json","stablePackId":"ecommerce.l3.scheduled-restocks"}],"id":"selected-source-058","scenario":{"level":3,"writeUrlPattern":null},"source":"scenarios/03-scheduled-restocks.json"},{"checkGroups":[{"checkGroupId":"server-time","feature":{"actors":["admin","watcher"],"criteria":[{"id":"312a","steps":[{"actor":"watcher","do":"wait","ms":30000},{"actor":"watcher","do":"reload","settleMs":2000},{"atMost":100000,"do":"expectElapsed","since":"restock-start"},{"do":"dbExpectStock","item":"Espresso Machine","plus":0,"relativeTo":"before"},{"actor":"admin","count":1,"do":"expect","testid":"pending-restock-item"},{"atMost":100000,"do":"expectElapsed","since":"restock-start"},{"actor":"admin","do":"wait","ms":130000,"since":"restock-start-accepted"},{"do":"dbExpectStock","item":"Espresso Machine","plus":4,"relativeTo":"before","within":10000},{"actor":"admin","do":"reload","settleMs":2000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"admin-link","within":1000},{"actor":"admin","do":"click","ifAvailable":true,"testid":"restocks-link","within":1000},{"actor":"admin","do":"expect","testid":"schedule-restock-submit"},{"absent":true,"actor":"admin","do":"expect","testid":"pending-restock-item"}]}],"id":312,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"click","testid":"admin-link"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"restocks-link","within":1000},{"as":"before","do":"dbRecordStock","item":"Espresso Machine"},{"actor":"admin","do":"fill","testid":"schedule-restock-item","text":"Espresso Machine"},{"actor":"admin","do":"fill","testid":"schedule-restock-warehouse","text":"West"},{"actor":"admin","do":"fill","testid":"schedule-restock-qty","text":"4"},{"actor":"admin","do":"fill","testid":"schedule-restock-delay","text":"120"},{"as":"restock-start","do":"recordTime"},{"actor":"admin","do":"click","testid":"schedule-restock-submit"},{"actor":"admin","count":1,"do":"expect","testid":"pending-restock-item","within":10000},{"as":"restock-start-accepted","do":"recordTime"},{"do":"dbExpectStock","item":"Espresso Machine","plus":0,"relativeTo":"before"},{"do":"restartBackend","settleMs":15000},{"actor":"watcher","do":"reload","settleMs":3000},{"actor":"admin","do":"reload","settleMs":3000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"admin-link","within":1000},{"actor":"admin","do":"click","ifAvailable":true,"testid":"restocks-link","within":1000},{"actor":"admin","do":"expect","testid":"schedule-restock-submit"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.l3.server-time-specifications","requiresFeatures":["ecommerce.l3.scheduled-restocks-features"],"role":"guarantee","source":"scenarios/03-server-time.json","stablePackId":"ecommerce.l3.server-time"},{"checkGroupId":"server-time","feature":{"actors":["customer","watcher"],"criteria":[{"id":"313a","steps":[{"actor":"watcher","do":"wait","ms":100000},{"actor":"watcher","do":"reload","settleMs":1000},{"actor":"watcher","do":"expectNumber","in":{"contains":"Air Purifier","testid":"item-card"},"plus":0,"relativeTo":"before","testid":"item-stock","within":30000}]}],"id":313,"setup":[{"actor":"customer","do":"signUp","name":"server-clock"},{"actor":"watcher","as":"before","do":"recordNumber","in":{"contains":"Air Purifier","testid":"item-card"},"testid":"item-stock"},{"actor":"customer","do":"click","in":{"contains":"Air Purifier","testid":"item-card"},"testid":"add-to-cart"},{"actor":"watcher","do":"reload","settleMs":1000},{"actor":"watcher","do":"expectNumber","in":{"contains":"Air Purifier","testid":"item-card"},"plus":-1,"relativeTo":"before","testid":"item-stock","within":10000},{"actor":"customer","do":"closeClient"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.l3.server-time-specifications","requiresFeatures":["ecommerce.l3.reservations-features"],"role":"guarantee","source":"scenarios/03-server-time.json","stablePackId":"ecommerce.l3.server-time"}],"id":"selected-source-059","scenario":{"level":3,"writeUrlPattern":null},"source":"scenarios/03-server-time.json"},{"checkGroups":[{"checkGroupId":"account-state-recovery","feature":{"actors":["shopper","peer"],"criteria":[{"id":"105b","steps":[{"actor":"shopper","do":"setOffline","offline":true,"settleMs":3000},{"actor":"peer","do":"click","in":{"contains":"Headphones","testid":"item-card"},"testid":"add-to-cart"},{"actor":"shopper","do":"setOffline","offline":false,"settleMs":6000},{"actor":"shopper","contains":"pat","do":"expect","testid":"current-user"},{"actor":"shopper","do":"click","testid":"cart-toggle","unlessVisible":"cart-total"},{"actor":"shopper","contains":"Keyboard","do":"expect","testid":"cart-item"},{"actor":"shopper","contains":"Headphones","do":"expect","testid":"cart-item"}]}],"id":105,"setup":[{"actor":"shopper","do":"signUp","name":"pat"},{"actor":"peer","do":"signIn","name":"pat"},{"actor":"shopper","do":"click","in":{"contains":"Keyboard","testid":"item-card"},"testid":"add-to-cart"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.state-durability","requiresFeatures":["ecommerce.feature.accounts","ecommerce.feature.checkout"],"role":"guarantee","source":"scenarios/progression-account-state-reconnect.json"}],"id":"selected-source-060","scenario":{"level":1,"writeUrlPattern":null},"source":"scenarios/progression-account-state-reconnect.json"},{"checkGroups":[{"checkGroupId":"account-state-recovery","feature":{"actors":["shopper"],"criteria":[{"id":"105a","steps":[{"actor":"shopper","do":"click","in":{"contains":"Headphones","testid":"item-card"},"testid":"add-to-cart"},{"actor":"shopper","do":"click","testid":"cart-toggle","unlessVisible":"cart-total"},{"actor":"shopper","do":"click","settleMs":1500,"testid":"checkout-submit"},{"actor":"shopper","do":"click","ifAvailable":true,"testid":"overlay-close"},{"actor":"shopper","do":"click","ifAvailable":true,"settleMs":2500,"testid":"catalog-link"},{"actor":"shopper","do":"click","in":{"contains":"Keyboard","testid":"item-card"},"testid":"add-to-cart"},{"actor":"shopper","do":"click","testid":"cart-toggle","unlessVisible":"cart-total"},{"actor":"shopper","contains":"Keyboard","do":"expect","testid":"cart-item","within":10000},{"actor":"shopper","do":"reload","settleMs":4000},{"actor":"shopper","contains":"pat","do":"expect","testid":"current-user"},{"actor":"shopper","do":"click","testid":"cart-toggle","unlessVisible":"cart-total"},{"actor":"shopper","contains":"Keyboard","do":"expect","testid":"cart-item"},{"actor":"shopper","do":"reload","settleMs":2500},{"actor":"shopper","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"shopper","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"shopper","contains":"Headphones","count":1,"do":"expect","testid":"order-item"},{"do":"restartBackend","settleMs":1000},{"actor":"shopper","do":"freshClient"},{"actor":"shopper-fresh","do":"signIn","name":"pat"},{"actor":"shopper-fresh","do":"click","testid":"cart-toggle","unlessVisible":"cart-total"},{"actor":"shopper-fresh","contains":"Keyboard","count":1,"do":"expect","testid":"cart-item"},{"actor":"shopper-fresh","do":"click","ifAvailable":true,"testid":"overlay-close"},{"actor":"shopper-fresh","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"shopper-fresh","contains":"Headphones","count":1,"do":"expect","testid":"order-item"}]}],"id":105,"setup":[{"actor":"shopper","do":"signUp","name":"pat"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.state-durability","requiresFeatures":["ecommerce.feature.accounts","ecommerce.feature.checkout"],"role":"guarantee","source":"scenarios/progression-account-state-reload.json"}],"id":"selected-source-061","scenario":{"level":1,"writeUrlPattern":null},"source":"scenarios/progression-account-state-reload.json"},{"checkGroups":[{"checkGroupId":"automatic-reorder-access","feature":{"actors":["staff","customer"],"criteria":[{"id":"502c","steps":[{"absent":true,"actor":"customer","do":"expect","testid":"reorder-link"},{"actor":"staff","do":"fill","testid":"reorder-item","text":"Desk Lamp"},{"actor":"staff","do":"fill","testid":"reorder-threshold","text":"1"},{"actor":"staff","do":"fill","testid":"reorder-quantity","text":"9"},{"action":"saveReorderRule","actor":"customer","do":"callAction","from":"staff","input":{"attribute":"data-action-input","testid":"reorder-submit"},"namedAction":{"args":[0,1,9],"id":"saveReorderRule","method":"PUT","params":[{"in":"path","name":"itemId","placeholder":"{itemId}","wireType":"u64"},{"in":"body","name":"threshold"},{"in":"body","name":"quantity"}],"path":"/api/reorders/{itemId}","reducer":"save_reorder_rule"}},{"actor":"customer","do":"expectActionOutcome","outcome":"refused","routeProvenBy":"staff"},{"actor":"staff","do":"reload","settleMs":1000},{"actor":"staff","do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026","readyTestid":"current-user"},{"actor":"staff","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"staff","do":"click","testid":"reorder-link","unlessVisible":"reorder-submit"},{"actor":"staff","attribute":"data-threshold","contains":"Desk Lamp","count":1,"do":"expect","testid":"reorder-rule-item","value":"2"},{"actor":"staff","attribute":"data-quantity","contains":"Desk Lamp","do":"expect","testid":"reorder-rule-item","value":"5"}]}],"id":502,"setup":[{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"staff","do":"expect","testid":"reorder-link","within":6000},{"actor":"staff","do":"click","testid":"reorder-link"},{"actor":"staff","do":"fill","testid":"reorder-item","text":"Desk Lamp"},{"actor":"staff","do":"fill","testid":"reorder-threshold","text":"2"},{"actor":"staff","do":"fill","testid":"reorder-quantity","text":"5"},{"action":"saveReorderRule","actor":"staff","do":"callAction","input":{"attribute":"data-action-input","testid":"reorder-submit"},"namedAction":{"args":[0,2,5],"id":"saveReorderRule","method":"PUT","params":[{"in":"path","name":"itemId","placeholder":"{itemId}","wireType":"u64"},{"in":"body","name":"threshold"},{"in":"body","name":"quantity"}],"path":"/api/reorders/{itemId}","reducer":"save_reorder_rule"}},{"actor":"staff","do":"expectActionOutcome","outcome":"accepted"},{"actor":"staff","do":"reload","settleMs":1000},{"actor":"staff","do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026","readyTestid":"current-user"},{"actor":"staff","do":"click","testid":"reorder-link","unlessVisible":"reorder-submit"},{"actor":"staff","contains":"Desk Lamp","do":"expectElementCount","equals":1,"testid":"reorder-rule-item","within":10000},{"actor":"customer","do":"signUp","name":"reorder-customer"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","requiresFeatures":["ecommerce.progression.automatic-reorder"],"role":"guarantee","source":"scenarios/progression-automatic-reorder-access.json"}],"id":"selected-source-062","scenario":{"level":5,"writeUrlPattern":null},"source":"scenarios/progression-automatic-reorder-access.json"},{"checkGroups":[{"checkGroupId":"automatic-reorder-deduplication","feature":{"actors":["staff","admin","buyer-a","buyer-b","buyer-c"],"criteria":[{"id":"502b","steps":[{"action":"buy","actor":"buyer-b","do":"callAction","input":{"attribute":"data-buy-input","contains":"Desk Lamp","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"}},{"actor":"buyer-b","do":"expectActionOutcome","outcome":"accepted"},{"action":"buy","actor":"buyer-c","do":"callAction","input":{"attribute":"data-buy-input","contains":"Desk Lamp","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"}},{"actor":"buyer-c","do":"expectActionOutcome","outcome":"accepted"},{"do":"dbExpectStock","equals":0,"item":"Desk Lamp"},{"actor":"admin","do":"reload","settleMs":1000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"admin","do":"click","testid":"admin-link","unlessVisible":"admin-revenue"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"restocks-link","within":1000},{"actor":"admin","do":"expect","testid":"schedule-restock-submit"},{"actor":"admin","do":"expectElementCount","equals":1,"testid":"pending-restock-item","within":10000},{"actor":"admin","attribute":"data-quantity","contains":"Desk Lamp","count":1,"do":"expect","testid":"pending-restock-item","value":"5"}]}],"id":502,"setup":[{"do":"dbSetStock","item":"Desk Lamp","quantity":2,"settleMs":2000,"warehouse":"East"},{"do":"dbSetStock","item":"Desk Lamp","quantity":1,"settleMs":2000,"warehouse":"West"},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"staff","do":"expect","testid":"reorder-link","within":6000},{"actor":"staff","do":"click","testid":"reorder-link"},{"actor":"staff","do":"fill","testid":"reorder-item","text":"Desk Lamp"},{"actor":"staff","do":"fill","testid":"reorder-threshold","text":"2"},{"actor":"staff","do":"fill","testid":"reorder-quantity","text":"5"},{"action":"saveReorderRule","actor":"staff","do":"callAction","input":{"attribute":"data-action-input","testid":"reorder-submit"},"namedAction":{"args":[0,2,5],"id":"saveReorderRule","method":"PUT","params":[{"in":"path","name":"itemId","placeholder":"{itemId}","wireType":"u64"},{"in":"body","name":"threshold"},{"in":"body","name":"quantity"}],"path":"/api/reorders/{itemId}","reducer":"save_reorder_rule"}},{"actor":"staff","do":"expectActionOutcome","outcome":"accepted"},{"actor":"staff","do":"reload","settleMs":1000},{"actor":"staff","do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026","readyTestid":"current-user"},{"actor":"staff","do":"click","testid":"reorder-link","unlessVisible":"reorder-submit"},{"actor":"staff","contains":"Desk Lamp","do":"expectElementCount","equals":1,"testid":"reorder-rule-item","within":10000},{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"click","testid":"admin-link"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"restocks-link","within":1000},{"actor":"buyer-a","do":"signUp","name":"reorder-a"},{"actor":"buyer-b","do":"signUp","name":"reorder-b"},{"actor":"buyer-c","do":"signUp","name":"reorder-c"},{"actor":"admin","do":"reload","settleMs":1000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"admin","do":"click","testid":"admin-link","unlessVisible":"admin-revenue"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"restocks-link","within":1000},{"actor":"admin","do":"expect","testid":"schedule-restock-submit"},{"actor":"admin","do":"expectElementCount","equals":0,"testid":"pending-restock-item"},{"action":"buy","actor":"buyer-a","do":"callAction","input":{"attribute":"data-buy-input","contains":"Desk Lamp","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"}},{"actor":"buyer-a","do":"expectActionOutcome","outcome":"accepted"},{"do":"dbExpectStock","equals":2,"item":"Desk Lamp"},{"actor":"admin","do":"reload","settleMs":1000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"admin","do":"click","testid":"admin-link","unlessVisible":"admin-revenue"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"restocks-link","within":1000},{"actor":"admin","do":"expect","testid":"schedule-restock-submit"},{"actor":"admin","do":"expectElementCount","equals":1,"testid":"pending-restock-item","within":10000},{"actor":"admin","attribute":"data-quantity","contains":"Desk Lamp","count":1,"do":"expect","testid":"pending-restock-item","value":"5"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.transactional-integrity","requiresFeatures":["ecommerce.feature.purchasing","ecommerce.progression.automatic-reorder"],"role":"guarantee","source":"scenarios/progression-automatic-reorder-duplicate.json"}],"id":"selected-source-063","scenario":{"level":5,"writeUrlPattern":null},"source":"scenarios/progression-automatic-reorder-duplicate.json"},{"checkGroups":[{"checkGroupId":"automatic-reorder","feature":{"actors":["staff","admin","buyer-a"],"criteria":[{"id":"502a","steps":[{"actor":"admin","do":"reload","settleMs":1000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"admin","do":"click","testid":"admin-link","unlessVisible":"admin-revenue"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"restocks-link","within":1000},{"actor":"admin","do":"expect","testid":"schedule-restock-submit"},{"actor":"admin","do":"expectElementCount","equals":0,"testid":"pending-restock-item"},{"action":"buy","actor":"buyer-a","do":"callAction","input":{"attribute":"data-buy-input","contains":"Desk Lamp","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"}},{"actor":"buyer-a","do":"expectActionOutcome","outcome":"accepted"},{"do":"dbExpectStock","equals":2,"item":"Desk Lamp"},{"actor":"admin","do":"reload","settleMs":1000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"admin","do":"click","testid":"admin-link","unlessVisible":"admin-revenue"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"restocks-link","within":1000},{"actor":"admin","do":"expect","testid":"schedule-restock-submit"},{"actor":"admin","do":"expectElementCount","equals":1,"testid":"pending-restock-item","within":10000},{"actor":"admin","attribute":"data-quantity","contains":"Desk Lamp","count":1,"do":"expect","testid":"pending-restock-item","value":"5"}]}],"id":502,"setup":[{"do":"dbSetStock","item":"Desk Lamp","quantity":2,"settleMs":2000,"warehouse":"East"},{"do":"dbSetStock","item":"Desk Lamp","quantity":1,"settleMs":2000,"warehouse":"West"},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"staff","do":"expect","testid":"reorder-link","within":6000},{"actor":"staff","do":"click","testid":"reorder-link"},{"actor":"staff","do":"fill","testid":"reorder-item","text":"Desk Lamp"},{"actor":"staff","do":"fill","testid":"reorder-threshold","text":"2"},{"actor":"staff","do":"fill","testid":"reorder-quantity","text":"5"},{"action":"saveReorderRule","actor":"staff","do":"callAction","input":{"attribute":"data-action-input","testid":"reorder-submit"},"namedAction":{"args":[0,2,5],"id":"saveReorderRule","method":"PUT","params":[{"in":"path","name":"itemId","placeholder":"{itemId}","wireType":"u64"},{"in":"body","name":"threshold"},{"in":"body","name":"quantity"}],"path":"/api/reorders/{itemId}","reducer":"save_reorder_rule"}},{"actor":"staff","do":"expectActionOutcome","outcome":"accepted"},{"actor":"staff","do":"reload","settleMs":1000},{"actor":"staff","do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026","readyTestid":"current-user"},{"actor":"staff","do":"click","testid":"reorder-link","unlessVisible":"reorder-submit"},{"actor":"staff","contains":"Desk Lamp","do":"expectElementCount","equals":1,"testid":"reorder-rule-item","within":10000},{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"click","testid":"admin-link"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"restocks-link","within":1000},{"actor":"buyer-a","do":"signUp","name":"reorder-a"}]},"packId":"ecommerce.progression.automatic-reorder","requiresFeatures":["ecommerce.feature.purchasing"],"role":"feature","source":"scenarios/progression-automatic-reorder.json"}],"id":"selected-source-064","scenario":{"level":5,"writeUrlPattern":null},"source":"scenarios/progression-automatic-reorder.json"},{"checkGroups":[{"checkGroupId":"books-balance","feature":{"actors":["buyer","admin"],"criteria":[{"id":"107a","steps":[{"actor":"admin","do":"reload","settleMs":1000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"admin","do":"click","testid":"admin-link","unlessVisible":"admin-revenue"},{"actor":"admin","do":"expectNumber","plus":58,"relativeTo":"revenue-before","testid":"admin-revenue","within":10000}]},{"id":"107b","steps":[{"actor":"admin","do":"reload","settleMs":2000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"admin-link"},{"actor":"admin","do":"expectNumber","in":{"contains":"Laptop Stand","testid":"admin-item-row"},"plus":-2,"relativeTo":"stand-before","testid":"admin-stock"},{"actor":"buyer","do":"freshClient"},{"actor":"buyer-fresh","do":"expectNumber","in":{"contains":"Laptop Stand","testid":"item-card"},"plus":-2,"relativeTo":"stand-before","testid":"item-stock"}]}],"id":107,"setup":[{"actor":"buyer","do":"signUp","name":"sam"},{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"click","testid":"admin-link"},{"actor":"admin","as":"revenue-before","do":"recordNumber","testid":"admin-revenue"},{"actor":"admin","as":"stand-before","do":"recordNumber","in":{"contains":"Laptop Stand","testid":"admin-item-row"},"testid":"admin-stock"},{"action":"buy","actor":"buyer","do":"callAction","input":{"attribute":"data-buy-input","contains":"Laptop Stand","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"}},{"actor":"buyer","do":"expectActionOutcome","outcome":"accepted"},{"action":"buy","actor":"buyer","do":"callAction","input":{"attribute":"data-buy-input","contains":"Laptop Stand","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"}},{"actor":"buyer","do":"expectActionOutcome","outcome":"accepted"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.transactional-integrity","requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.warehouse-admin"],"role":"guarantee","source":"scenarios/progression-books-balance.json"}],"id":"selected-source-065","scenario":{"level":1,"writeUrlPattern":null},"source":"scenarios/progression-books-balance.json"},{"checkGroups":[{"checkGroupId":"bundle-checkout","feature":{"actors":["admin","buyer"],"criteria":[{"id":"741a","steps":[{"actor":"buyer","do":"click","in":{"contains":"Checkout bundle","testid":"bundle-card"},"settleMs":500,"testid":"bundle-add-to-cart"},{"do":"dbExpectStock","equals":4,"item":"Keyboard","warehouse":"East"},{"do":"dbExpectStock","equals":3,"item":"Desk Lamp","warehouse":"East"},{"actor":"buyer","do":"click","testid":"cart-toggle"},{"actor":"buyer","do":"click","testid":"checkout-submit"},{"actor":"buyer","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"buyer","do":"click","testid":"orders-toggle"},{"actor":"buyer","contains":"Checkout bundle","count":1,"do":"expect","testid":"order-item","within":10000},{"actor":"buyer","do":"expectNumber","equals":75,"in":{"contains":"Checkout bundle","testid":"order-item"},"testid":"payment-amount","within":10000},{"do":"dbExpectStock","equals":4,"item":"Keyboard","warehouse":"East"},{"do":"dbExpectStock","equals":3,"item":"Desk Lamp","warehouse":"East"},{"do":"dbExpectStock","equals":0,"item":"Keyboard","warehouse":"West"},{"do":"dbExpectStock","equals":0,"item":"Desk Lamp","warehouse":"West"}]}],"id":741,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"click","testid":"bundles-link","unlessVisible":"bundle-name-input"},{"actor":"buyer","do":"signUp","name":"bundle-checkout"},{"do":"dbSetStock","item":"Keyboard","quantity":6,"settleMs":0,"warehouse":"East"},{"do":"dbSetStock","item":"Keyboard","quantity":0,"settleMs":0,"warehouse":"West"},{"do":"dbSetStock","item":"Desk Lamp","quantity":4,"settleMs":0,"warehouse":"East"},{"do":"dbSetStock","item":"Desk Lamp","quantity":0,"settleMs":0,"warehouse":"West"},{"actor":"admin","do":"fill","testid":"bundle-name-input","text":"Checkout bundle"},{"actor":"admin","do":"fill","testid":"bundle-price-input","text":"75.00"},{"actor":"admin","do":"fill","testid":"bundle-components-input","text":"[{\"item\":\"Keyboard\",\"quantity\":2},{\"item\":\"Desk Lamp\",\"quantity\":1}]"},{"actor":"admin","do":"click","testid":"bundle-save"},{"actor":"admin","contains":"Checkout bundle","do":"expect","testid":"bundle-card","within":10000},{"actor":"buyer","do":"click","testid":"bundles-link","unlessVisible":"bundle-card"}]},"packId":"ecommerce.feature.bundle-checkout","role":"feature","source":"scenarios/progression-bundle-checkout.json"},{"checkGroupId":"bundle-744","feature":{"actors":["admin","a","b"],"criteria":[{"id":"744a","steps":[{"action":"addBundleToCart","actors":["a","b"],"do":"callConcurrently","input":{"attribute":"data-bundle-input","contains":"Scarce bundle","testid":"bundle-card"},"namedAction":{"args":[0],"id":"addBundleToCart","params":[{"in":"body","name":"bundleId","wireType":"u64"}],"path":"/api/cart/bundles","reducer":"add_bundle_to_cart"},"settleMs":1000},{"accepted":1,"do":"expectCallOutcomes"},{"do":"dbExpectStock","equals":0,"item":"Keyboard","warehouse":"East"},{"do":"dbExpectStock","equals":0,"item":"Desk Lamp","warehouse":"East"},{"actor":"a","do":"reload","settleMs":1000},{"actor":"b","do":"reload","settleMs":1000},{"actor":"a","do":"click","testid":"cart-toggle"},{"actor":"b","do":"click","testid":"cart-toggle"},{"actors":["a","b"],"contains":"Scarce bundle","do":"expectActorsWith","equals":1,"maxEach":1,"testid":"cart-item"},{"actor":"a","do":"click","ifAvailable":true,"in":{"contains":"Scarce bundle","testid":"cart-item"},"settleMs":500,"testid":"bundle-remove"},{"actor":"b","do":"click","ifAvailable":true,"in":{"contains":"Scarce bundle","testid":"cart-item"},"settleMs":500,"testid":"bundle-remove"},{"do":"dbExpectStock","equals":2,"item":"Keyboard","warehouse":"East"},{"do":"dbExpectStock","equals":1,"item":"Desk Lamp","warehouse":"East"}]}],"id":744,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"click","testid":"bundles-link","unlessVisible":"bundle-name-input"},{"actor":"a","do":"signUp","name":"bundle-race-a"},{"actor":"b","do":"signUp","name":"bundle-race-b"},{"do":"dbSetStock","item":"Keyboard","quantity":2,"settleMs":0,"warehouse":"East"},{"do":"dbSetStock","item":"Keyboard","quantity":0,"settleMs":0,"warehouse":"West"},{"do":"dbSetStock","item":"Desk Lamp","quantity":1,"settleMs":0,"warehouse":"East"},{"do":"dbSetStock","item":"Desk Lamp","quantity":0,"settleMs":0,"warehouse":"West"},{"actor":"admin","do":"fill","testid":"bundle-name-input","text":"Scarce bundle"},{"actor":"admin","do":"fill","testid":"bundle-price-input","text":"75.00"},{"actor":"admin","do":"fill","testid":"bundle-components-input","text":"[{\"item\":\"Keyboard\",\"quantity\":2},{\"item\":\"Desk Lamp\",\"quantity\":1}]"},{"actor":"admin","do":"click","testid":"bundle-save"},{"actor":"admin","contains":"Scarce bundle","do":"expect","testid":"bundle-card","within":10000},{"actor":"a","do":"click","testid":"bundles-link","unlessVisible":"bundle-card"},{"actor":"b","do":"click","testid":"bundles-link","unlessVisible":"bundle-card"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.bundle-integrity","requiresFeatures":["ecommerce.feature.bundle-checkout"],"role":"guarantee","source":"scenarios/progression-bundle-checkout.json"},{"checkGroupId":"bundle-745","feature":{"actors":["admin","buyer"],"criteria":[{"id":"745a","steps":[{"action":"addBundleToCart","actor":"buyer","do":"callAction","input":{"attribute":"data-bundle-input","contains":"Unavailable bundle","testid":"bundle-card"},"namedAction":{"args":[0],"id":"addBundleToCart","params":[{"in":"body","name":"bundleId","wireType":"u64"}],"path":"/api/cart/bundles","reducer":"add_bundle_to_cart"},"settleMs":1000},{"actor":"buyer","do":"expectActionOutcome","outcome":"application-refused"},{"do":"dbExpectStock","equals":2,"item":"Keyboard","warehouse":"East"},{"do":"dbExpectStock","equals":0,"item":"Desk Lamp","warehouse":"East"},{"actor":"buyer","do":"click","testid":"cart-toggle"},{"absent":true,"actor":"buyer","contains":"Unavailable bundle","do":"expect","testid":"cart-item","within":10000}]}],"id":745,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"click","testid":"bundles-link","unlessVisible":"bundle-name-input"},{"actor":"buyer","do":"signUp","name":"bundle-partial"},{"do":"dbSetStock","item":"Keyboard","quantity":2,"settleMs":0,"warehouse":"East"},{"do":"dbSetStock","item":"Keyboard","quantity":0,"settleMs":0,"warehouse":"West"},{"do":"dbSetStock","item":"Desk Lamp","quantity":0,"settleMs":0,"warehouse":"East"},{"do":"dbSetStock","item":"Desk Lamp","quantity":0,"settleMs":0,"warehouse":"West"},{"actor":"admin","do":"fill","testid":"bundle-name-input","text":"Unavailable bundle"},{"actor":"admin","do":"fill","testid":"bundle-price-input","text":"75.00"},{"actor":"admin","do":"fill","testid":"bundle-components-input","text":"[{\"item\":\"Keyboard\",\"quantity\":2},{\"item\":\"Desk Lamp\",\"quantity\":1}]"},{"actor":"admin","do":"click","testid":"bundle-save"},{"actor":"admin","contains":"Unavailable bundle","do":"expect","testid":"bundle-card","within":10000},{"actor":"buyer","do":"click","testid":"bundles-link","unlessVisible":"bundle-card"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.bundle-integrity","requiresFeatures":["ecommerce.feature.bundle-checkout"],"role":"guarantee","source":"scenarios/progression-bundle-checkout.json"},{"checkGroupId":"bundle-746","feature":{"actors":["admin","buyer"],"criteria":[{"id":"746a","steps":[{"actor":"buyer","do":"click","in":{"contains":"Expiring bundle","testid":"bundle-card"},"settleMs":500,"testid":"bundle-add-to-cart"},{"do":"dbExpectStock","equals":4,"item":"Keyboard","warehouse":"East"},{"do":"dbExpectStock","equals":3,"item":"Desk Lamp","warehouse":"East"},{"do":"restartBackend","settleMs":1500},{"actor":"buyer","do":"wait","ms":92000},{"actor":"buyer","do":"reload","settleMs":1000},{"actor":"buyer","do":"ensureSignedIn","name":"bundle-expiry","readyTestid":"current-user"},{"actor":"buyer","do":"click","testid":"cart-toggle"},{"actor":"buyer","do":"expect","in":{"contains":"Expiring bundle","testid":"cart-item"},"testid":"cart-item-expired","within":10000},{"do":"dbExpectStock","equals":6,"item":"Keyboard","warehouse":"East"},{"do":"dbExpectStock","equals":4,"item":"Desk Lamp","warehouse":"East"},{"do":"restartBackend","settleMs":1500},{"do":"dbExpectStock","equals":6,"item":"Keyboard","warehouse":"East"},{"do":"dbExpectStock","equals":4,"item":"Desk Lamp","warehouse":"East"}]}],"id":746,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"click","testid":"bundles-link","unlessVisible":"bundle-name-input"},{"actor":"buyer","do":"signUp","name":"bundle-expiry"},{"do":"dbSetStock","item":"Keyboard","quantity":6,"settleMs":0,"warehouse":"East"},{"do":"dbSetStock","item":"Keyboard","quantity":0,"settleMs":0,"warehouse":"West"},{"do":"dbSetStock","item":"Desk Lamp","quantity":4,"settleMs":0,"warehouse":"East"},{"do":"dbSetStock","item":"Desk Lamp","quantity":0,"settleMs":0,"warehouse":"West"},{"actor":"admin","do":"fill","testid":"bundle-name-input","text":"Expiring bundle"},{"actor":"admin","do":"fill","testid":"bundle-price-input","text":"75.00"},{"actor":"admin","do":"fill","testid":"bundle-components-input","text":"[{\"item\":\"Keyboard\",\"quantity\":2},{\"item\":\"Desk Lamp\",\"quantity\":1}]"},{"actor":"admin","do":"click","testid":"bundle-save"},{"actor":"admin","contains":"Expiring bundle","do":"expect","testid":"bundle-card","within":10000},{"actor":"buyer","do":"click","testid":"bundles-link","unlessVisible":"bundle-card"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.bundle-integrity","requiresFeatures":["ecommerce.feature.bundle-checkout"],"role":"guarantee","source":"scenarios/progression-bundle-checkout.json"},{"checkGroupId":"bundle-747","feature":{"actors":["admin","a","b"],"criteria":[{"id":"747a","steps":[{"action":"checkout","actors":["a","b"],"do":"callConcurrently","settleMs":1000},{"accepted":1,"do":"expectCallOutcomes"},{"actor":"a","do":"reload","settleMs":1000},{"actor":"a","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"a","do":"click","testid":"orders-toggle"},{"actor":"a","contains":"Repeated bundle","count":1,"do":"expect","testid":"order-item","within":10000},{"actor":"a","do":"expectNumber","equals":75,"in":{"contains":"Repeated bundle","testid":"order-item"},"testid":"payment-amount","within":10000},{"do":"dbExpectStock","equals":4,"item":"Keyboard","warehouse":"East"},{"do":"dbExpectStock","equals":3,"item":"Desk Lamp","warehouse":"East"}]}],"id":747,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"click","testid":"bundles-link","unlessVisible":"bundle-name-input"},{"actor":"a","do":"signUp","name":"bundle-repeat"},{"actor":"b","do":"signIn","name":"bundle-repeat"},{"do":"dbSetStock","item":"Keyboard","quantity":6,"settleMs":0,"warehouse":"East"},{"do":"dbSetStock","item":"Keyboard","quantity":0,"settleMs":0,"warehouse":"West"},{"do":"dbSetStock","item":"Desk Lamp","quantity":4,"settleMs":0,"warehouse":"East"},{"do":"dbSetStock","item":"Desk Lamp","quantity":0,"settleMs":0,"warehouse":"West"},{"actor":"admin","do":"fill","testid":"bundle-name-input","text":"Repeated bundle"},{"actor":"admin","do":"fill","testid":"bundle-price-input","text":"75.00"},{"actor":"admin","do":"fill","testid":"bundle-components-input","text":"[{\"item\":\"Keyboard\",\"quantity\":2},{\"item\":\"Desk Lamp\",\"quantity\":1}]"},{"actor":"admin","do":"click","testid":"bundle-save"},{"actor":"admin","contains":"Repeated bundle","do":"expect","testid":"bundle-card","within":10000},{"actor":"a","do":"click","testid":"bundles-link","unlessVisible":"bundle-card"},{"actor":"a","do":"click","in":{"contains":"Repeated bundle","testid":"bundle-card"},"settleMs":500,"testid":"bundle-add-to-cart"},{"do":"dbExpectStock","equals":4,"item":"Keyboard","warehouse":"East"},{"do":"dbExpectStock","equals":3,"item":"Desk Lamp","warehouse":"East"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.bundle-integrity","requiresFeatures":["ecommerce.feature.bundle-checkout"],"role":"guarantee","source":"scenarios/progression-bundle-checkout.json"}],"id":"selected-source-066","scenario":{"level":5,"writeUrlPattern":null},"source":"scenarios/progression-bundle-checkout.json"},{"checkGroups":[{"checkGroupId":"bundle-returns","feature":{"actors":["admin","buyer","staff"],"criteria":[{"id":"742a","steps":[{"actor":"admin","do":"fill","testid":"bundle-name-input","text":"Historical bundle"},{"actor":"admin","do":"fill","testid":"bundle-price-input","text":"9.00"},{"actor":"admin","do":"fill","testid":"bundle-components-input","text":"[{\"item\":\"Keyboard\",\"quantity\":1},{\"item\":\"Desk Lamp\",\"quantity\":3}]"},{"actor":"admin","do":"click","testid":"bundle-save"},{"actor":"admin","contains":"Historical bundle","do":"expect","testid":"bundle-card","within":10000},{"actor":"buyer","do":"click","in":{"contains":"Historical bundle","testid":"order-item"},"testid":"return-bundle"},{"actor":"buyer","do":"expect","ignoreCase":true,"in":{"contains":"Historical bundle","testid":"order-item"},"testid":"order-status","value":"returned","within":10000},{"actor":"buyer","do":"expectNumber","equals":75,"in":{"contains":"Historical bundle","testid":"order-item"},"testid":"bundle-refund-amount","within":10000},{"do":"dbExpectStock","equals":6,"item":"Keyboard","warehouse":"East"},{"do":"dbExpectStock","equals":4,"item":"Desk Lamp","warehouse":"East"},{"do":"dbExpectStock","equals":0,"item":"Keyboard","warehouse":"West"},{"do":"dbExpectStock","equals":0,"item":"Desk Lamp","warehouse":"West"}]}],"id":742,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"click","testid":"bundles-link","unlessVisible":"bundle-name-input"},{"actor":"buyer","do":"signUp","name":"Historical bundle"},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"do":"dbSetStock","item":"Keyboard","quantity":6,"settleMs":0,"warehouse":"East"},{"do":"dbSetStock","item":"Keyboard","quantity":0,"settleMs":0,"warehouse":"West"},{"do":"dbSetStock","item":"Desk Lamp","quantity":4,"settleMs":0,"warehouse":"East"},{"do":"dbSetStock","item":"Desk Lamp","quantity":0,"settleMs":0,"warehouse":"West"},{"actor":"admin","do":"fill","testid":"bundle-name-input","text":"Historical bundle"},{"actor":"admin","do":"fill","testid":"bundle-price-input","text":"75.00"},{"actor":"admin","do":"fill","testid":"bundle-components-input","text":"[{\"item\":\"Keyboard\",\"quantity\":2},{\"item\":\"Desk Lamp\",\"quantity\":1}]"},{"actor":"admin","do":"click","testid":"bundle-save"},{"actor":"admin","contains":"Historical bundle","do":"expect","testid":"bundle-card","within":10000},{"actor":"buyer","do":"click","testid":"bundles-link","unlessVisible":"bundle-card"},{"actor":"buyer","do":"click","in":{"contains":"Historical bundle","testid":"bundle-card"},"testid":"bundle-add-to-cart"},{"actor":"buyer","do":"click","testid":"cart-toggle"},{"actor":"buyer","do":"click","testid":"checkout-submit"},{"actor":"buyer","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"buyer","do":"click","testid":"orders-toggle"},{"actor":"buyer","contains":"Historical bundle","count":1,"do":"expect","testid":"order-item","within":10000},{"actor":"buyer","do":"expectNumber","equals":75,"in":{"contains":"Historical bundle","testid":"order-item"},"testid":"payment-amount","within":10000},{"do":"dbExpectStock","equals":4,"item":"Keyboard","warehouse":"East"},{"do":"dbExpectStock","equals":3,"item":"Desk Lamp","warehouse":"East"},{"actor":"staff","do":"click","testid":"staff-link"},{"actor":"staff","contains":"Historical bundle","do":"expect","testid":"queue-item","within":10000},{"actor":"staff","do":"click","in":{"contains":"Historical bundle","testid":"queue-item"},"testid":"ship-submit"},{"actor":"buyer","do":"expect","ignoreCase":true,"in":{"contains":"Historical bundle","testid":"order-item"},"testid":"order-status","value":"shipped","within":10000}]},"packId":"ecommerce.feature.bundle-returns","role":"feature","source":"scenarios/progression-bundle-returns.json"},{"checkGroupId":"bundle-742","feature":{"actors":["admin","buyer","staff"],"criteria":[{"id":"742b","steps":[{"do":"restartBackend","settleMs":1500},{"actor":"buyer","do":"reload","settleMs":1000},{"actor":"buyer","do":"ensureSignedIn","name":"Historical bundle","readyTestid":"current-user"},{"actor":"buyer","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"buyer","do":"click","testid":"orders-toggle"},{"action":"returnBundle","actor":"buyer","do":"callAction","input":{"attribute":"data-bundle-return-input","contains":"Historical bundle","testid":"order-item"},"namedAction":{"args":[0],"id":"returnBundle","params":[{"in":"path","name":"orderId","placeholder":":orderId","wireType":"u64"}],"path":"/api/bundle-orders/:orderId/return","reducer":"return_bundle"},"settleMs":1000},{"actor":"buyer","do":"reload","settleMs":1000},{"actor":"buyer","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"buyer","do":"click","testid":"orders-toggle"},{"actor":"buyer","do":"expectNumber","equals":75,"in":{"contains":"Historical bundle","testid":"order-item"},"testid":"bundle-refund-amount","within":10000},{"do":"dbExpectStock","equals":6,"item":"Keyboard","warehouse":"East"},{"do":"dbExpectStock","equals":4,"item":"Desk Lamp","warehouse":"East"}]}],"id":742,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"click","testid":"bundles-link","unlessVisible":"bundle-name-input"},{"actor":"buyer","do":"signUp","name":"Historical bundle"},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"do":"dbSetStock","item":"Keyboard","quantity":6,"settleMs":0,"warehouse":"East"},{"do":"dbSetStock","item":"Keyboard","quantity":0,"settleMs":0,"warehouse":"West"},{"do":"dbSetStock","item":"Desk Lamp","quantity":4,"settleMs":0,"warehouse":"East"},{"do":"dbSetStock","item":"Desk Lamp","quantity":0,"settleMs":0,"warehouse":"West"},{"actor":"admin","do":"fill","testid":"bundle-name-input","text":"Historical bundle"},{"actor":"admin","do":"fill","testid":"bundle-price-input","text":"75.00"},{"actor":"admin","do":"fill","testid":"bundle-components-input","text":"[{\"item\":\"Keyboard\",\"quantity\":2},{\"item\":\"Desk Lamp\",\"quantity\":1}]"},{"actor":"admin","do":"click","testid":"bundle-save"},{"actor":"admin","contains":"Historical bundle","do":"expect","testid":"bundle-card","within":10000},{"actor":"buyer","do":"click","testid":"bundles-link","unlessVisible":"bundle-card"},{"actor":"buyer","do":"click","in":{"contains":"Historical bundle","testid":"bundle-card"},"testid":"bundle-add-to-cart"},{"actor":"buyer","do":"click","testid":"cart-toggle"},{"actor":"buyer","do":"click","testid":"checkout-submit"},{"actor":"buyer","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"buyer","do":"click","testid":"orders-toggle"},{"actor":"buyer","contains":"Historical bundle","count":1,"do":"expect","testid":"order-item","within":10000},{"actor":"buyer","do":"expectNumber","equals":75,"in":{"contains":"Historical bundle","testid":"order-item"},"testid":"payment-amount","within":10000},{"do":"dbExpectStock","equals":4,"item":"Keyboard","warehouse":"East"},{"do":"dbExpectStock","equals":3,"item":"Desk Lamp","warehouse":"East"},{"actor":"staff","do":"click","testid":"staff-link"},{"actor":"staff","contains":"Historical bundle","do":"expect","testid":"queue-item","within":10000},{"actor":"staff","do":"click","in":{"contains":"Historical bundle","testid":"queue-item"},"testid":"ship-submit"},{"actor":"buyer","do":"expect","ignoreCase":true,"in":{"contains":"Historical bundle","testid":"order-item"},"testid":"order-status","value":"shipped","within":10000}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.bundle-integrity","requiresFeatures":["ecommerce.feature.bundle-returns"],"role":"guarantee","source":"scenarios/progression-bundle-returns.json"},{"checkGroupId":"bundle-748","feature":{"actors":["admin","buyer","staff","other"],"criteria":[{"id":"748a","steps":[{"action":"returnBundle","actor":"other","do":"callAction","from":"buyer","input":{"attribute":"data-bundle-return-input","contains":"Private bundle","testid":"order-item"},"namedAction":{"args":[0],"id":"returnBundle","params":[{"in":"path","name":"orderId","placeholder":":orderId","wireType":"u64"}],"path":"/api/bundle-orders/:orderId/return","reducer":"return_bundle"},"settleMs":1000},{"actor":"other","do":"expectActionOutcome","outcome":"application-refused"},{"actor":"buyer","do":"reload","settleMs":1000},{"actor":"buyer","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"buyer","do":"click","testid":"orders-toggle"},{"actor":"buyer","do":"expect","ignoreCase":true,"in":{"contains":"Private bundle","testid":"order-item"},"testid":"order-status","value":"shipped","within":10000},{"do":"dbExpectStock","equals":4,"item":"Keyboard","warehouse":"East"},{"do":"dbExpectStock","equals":3,"item":"Desk Lamp","warehouse":"East"},{"actor":"buyer","do":"click","in":{"contains":"Private bundle","testid":"order-item"},"testid":"return-bundle"},{"actor":"buyer","do":"expectNumber","equals":75,"in":{"contains":"Private bundle","testid":"order-item"},"testid":"bundle-refund-amount","within":10000},{"do":"dbExpectStock","equals":6,"item":"Keyboard","warehouse":"East"},{"do":"dbExpectStock","equals":4,"item":"Desk Lamp","warehouse":"East"}]}],"id":748,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"click","testid":"bundles-link","unlessVisible":"bundle-name-input"},{"actor":"buyer","do":"signUp","name":"Private bundle"},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"do":"dbSetStock","item":"Keyboard","quantity":6,"settleMs":0,"warehouse":"East"},{"do":"dbSetStock","item":"Keyboard","quantity":0,"settleMs":0,"warehouse":"West"},{"do":"dbSetStock","item":"Desk Lamp","quantity":4,"settleMs":0,"warehouse":"East"},{"do":"dbSetStock","item":"Desk Lamp","quantity":0,"settleMs":0,"warehouse":"West"},{"actor":"admin","do":"fill","testid":"bundle-name-input","text":"Private bundle"},{"actor":"admin","do":"fill","testid":"bundle-price-input","text":"75.00"},{"actor":"admin","do":"fill","testid":"bundle-components-input","text":"[{\"item\":\"Keyboard\",\"quantity\":2},{\"item\":\"Desk Lamp\",\"quantity\":1}]"},{"actor":"admin","do":"click","testid":"bundle-save"},{"actor":"admin","contains":"Private bundle","do":"expect","testid":"bundle-card","within":10000},{"actor":"buyer","do":"click","testid":"bundles-link","unlessVisible":"bundle-card"},{"actor":"buyer","do":"click","in":{"contains":"Private bundle","testid":"bundle-card"},"testid":"bundle-add-to-cart"},{"actor":"buyer","do":"click","testid":"cart-toggle"},{"actor":"buyer","do":"click","testid":"checkout-submit"},{"actor":"buyer","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"buyer","do":"click","testid":"orders-toggle"},{"actor":"buyer","contains":"Private bundle","count":1,"do":"expect","testid":"order-item","within":10000},{"actor":"buyer","do":"expectNumber","equals":75,"in":{"contains":"Private bundle","testid":"order-item"},"testid":"payment-amount","within":10000},{"do":"dbExpectStock","equals":4,"item":"Keyboard","warehouse":"East"},{"do":"dbExpectStock","equals":3,"item":"Desk Lamp","warehouse":"East"},{"actor":"staff","do":"click","testid":"staff-link"},{"actor":"staff","contains":"Private bundle","do":"expect","testid":"queue-item","within":10000},{"actor":"staff","do":"click","in":{"contains":"Private bundle","testid":"queue-item"},"testid":"ship-submit"},{"actor":"buyer","do":"expect","ignoreCase":true,"in":{"contains":"Private bundle","testid":"order-item"},"testid":"order-status","value":"shipped","within":10000},{"actor":"other","do":"signUp","name":"bundle-other"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.bundle-integrity","requiresFeatures":["ecommerce.feature.bundle-returns"],"role":"guarantee","source":"scenarios/progression-bundle-returns.json"}],"id":"selected-source-067","scenario":{"level":6,"writeUrlPattern":null},"source":"scenarios/progression-bundle-returns.json"},{"checkGroups":[{"checkGroupId":"cart","feature":{"actors":["quantity","checkout"],"criteria":[{"id":"4a","steps":[{"actor":"quantity","do":"click","in":{"contains":"Headphones","testid":"item-card"},"testid":"add-to-cart"},{"actor":"quantity","do":"wait","ms":800},{"actor":"quantity","do":"click","ifAvailable":true,"testid":"overlay-close"},{"actor":"quantity","do":"click","ifAvailable":true,"testid":"catalog-link"},{"actor":"quantity","do":"click","in":{"contains":"Headphones","testid":"item-card"},"testid":"add-to-cart"},{"actor":"quantity","do":"click","testid":"cart-toggle","unlessVisible":"cart-total"},{"actor":"quantity","contains":"Headphones","count":1,"do":"expect","testid":"cart-item"},{"actor":"quantity","do":"expectNumber","equals":2,"in":{"contains":"Headphones","testid":"cart-item"},"testid":"cart-quantity"}]}],"id":4,"setup":[{"actor":"quantity","do":"signUp","name":"cart-quantity"},{"actor":"checkout","do":"signUp","name":"cart-checkout"}]},"packId":"ecommerce.feature.cart","role":"feature","source":"scenarios/progression-cart-checkout.json","stablePackId":"ecommerce.feature.cart-checkout"},{"checkGroupId":"cart","feature":{"actors":["quantity","checkout"],"criteria":[{"id":"4d","steps":[{"actor":"checkout","do":"expectNumber","equals":100,"in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"item-stock"},{"actor":"checkout","do":"click","in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"add-to-cart"},{"actor":"checkout","do":"click","testid":"cart-toggle","unlessVisible":"cart-total"},{"actor":"checkout","do":"expectNumber","equals":1,"testid":"cart-count"},{"actor":"checkout","do":"click","testid":"checkout-submit"},{"actor":"checkout","do":"wait","ms":1500},{"actor":"checkout","do":"reload","settleMs":2500},{"actor":"checkout","do":"ensureSignedIn","name":"cart-checkout","readyTestid":"current-user"},{"actor":"checkout","do":"click","testid":"cart-toggle","unlessVisible":"cart-total"},{"actor":"checkout","do":"expectNumber","equals":0,"testid":"cart-count"},{"actor":"checkout","do":"click","ifAvailable":true,"testid":"overlay-close"},{"actor":"checkout","do":"click","ifAvailable":true,"testid":"catalog-link"},{"actor":"checkout","do":"expectNumber","equals":99,"in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"item-stock"},{"actor":"checkout","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"checkout","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"checkout","contains":"Desk Lamp","count":1,"do":"expect","testid":"order-item"}]}],"id":4,"setup":[{"actor":"quantity","do":"signUp","name":"cart-quantity"},{"actor":"checkout","do":"signUp","name":"cart-checkout"}]},"packId":"ecommerce.feature.checkout","role":"feature","source":"scenarios/progression-cart-checkout.json","stablePackId":"ecommerce.feature.cart-checkout"}],"id":"selected-source-068","scenario":{"level":1,"writeUrlPattern":null},"source":"scenarios/progression-cart-checkout.json"},{"checkGroups":[{"checkGroupId":"cart-recovery","feature":{"actors":["available-shopper","partial-shopper"],"criteria":[{"id":"503a","steps":[{"actor":"available-shopper","do":"reload","settleMs":1000},{"actor":"available-shopper","do":"ensureSignedIn","name":"cart-recovery-available","readyTestid":"current-user"},{"actor":"available-shopper","do":"expect","testid":"expired-cart"},{"actor":"available-shopper","do":"expectNumber","equals":0,"testid":"cart-count"},{"actor":"available-shopper","as":"restore-available-shopper","do":"recordNumber","in":{"contains":"Keyboard","testid":"item-card"},"testid":"item-stock"},{"actor":"available-shopper","do":"click","in":{"testid":"expired-cart"},"testid":"restore-cart"},{"actor":"available-shopper","do":"click","testid":"cart-toggle"},{"actor":"available-shopper","contains":"Keyboard","do":"expect","testid":"cart-item"},{"absent":true,"actor":"available-shopper","do":"expect","testid":"cart-restore-warning"},{"actor":"available-shopper","do":"expectNumber","equals":1,"in":{"contains":"Keyboard","testid":"cart-item"},"testid":"cart-quantity"},{"actor":"available-shopper","do":"reload","settleMs":1000},{"actor":"available-shopper","do":"ensureSignedIn","name":"cart-recovery-available","readyTestid":"current-user"},{"actor":"available-shopper","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"available-shopper","do":"click","testid":"catalog-link","unlessVisible":"item-card"},{"actor":"available-shopper","do":"expectNumber","in":{"contains":"Keyboard","testid":"item-card"},"plus":-1,"relativeTo":"restore-available-shopper","testid":"item-stock"}]}],"id":503,"setup":[{"actor":"available-shopper","do":"signUp","name":"cart-recovery-available"},{"actor":"available-shopper","do":"click","in":{"contains":"Keyboard","testid":"item-card"},"testid":"add-to-cart"},{"actor":"partial-shopper","do":"signUp","name":"cart-recovery-partial"},{"actor":"partial-shopper","do":"click","in":{"contains":"Gaming Mouse","testid":"item-card"},"testid":"add-to-cart"},{"actor":"partial-shopper","do":"click","in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"add-to-cart"},{"actor":"available-shopper","do":"wait","ms":310000}]},"packId":"ecommerce.progression.cart-recovery","role":"feature","source":"scenarios/progression-cart-recovery.json"},{"checkGroupId":"cart-recovery","feature":{"actors":["available-shopper","partial-shopper"],"criteria":[{"id":"503b","steps":[{"actor":"partial-shopper","do":"reload","settleMs":1000},{"actor":"partial-shopper","do":"ensureSignedIn","name":"cart-recovery-partial","readyTestid":"current-user"},{"actor":"partial-shopper","do":"expect","testid":"expired-cart"},{"actor":"partial-shopper","do":"expectNumber","equals":0,"testid":"cart-count"},{"actor":"partial-shopper","as":"restore-partial-shopper","do":"recordNumber","in":{"contains":"Gaming Mouse","testid":"item-card"},"testid":"item-stock"},{"do":"dbSetStock","item":"Desk Lamp","quantity":0,"settleMs":2000,"warehouse":"East"},{"do":"dbSetStock","item":"Desk Lamp","quantity":0,"settleMs":2000,"warehouse":"West"},{"actor":"partial-shopper","do":"click","in":{"testid":"expired-cart"},"testid":"restore-cart"},{"actor":"partial-shopper","do":"click","testid":"cart-toggle"},{"actor":"partial-shopper","contains":"Gaming Mouse","do":"expect","testid":"cart-item"},{"absent":true,"actor":"partial-shopper","contains":"Desk Lamp","do":"expect","testid":"cart-item"},{"actor":"partial-shopper","contains":"Desk Lamp","do":"expect","testid":"cart-restore-warning"},{"actor":"partial-shopper","do":"expectNumber","equals":1,"in":{"contains":"Gaming Mouse","testid":"cart-item"},"testid":"cart-quantity"},{"actor":"partial-shopper","do":"reload","settleMs":1000},{"actor":"partial-shopper","do":"ensureSignedIn","name":"cart-recovery-partial","readyTestid":"current-user"},{"actor":"partial-shopper","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"partial-shopper","do":"click","testid":"catalog-link","unlessVisible":"item-card"},{"actor":"partial-shopper","do":"expectNumber","in":{"contains":"Gaming Mouse","testid":"item-card"},"plus":-1,"relativeTo":"restore-partial-shopper","testid":"item-stock"}]}],"id":503,"setup":[{"actor":"available-shopper","do":"signUp","name":"cart-recovery-available"},{"actor":"available-shopper","do":"click","in":{"contains":"Keyboard","testid":"item-card"},"testid":"add-to-cart"},{"actor":"partial-shopper","do":"signUp","name":"cart-recovery-partial"},{"actor":"partial-shopper","do":"click","in":{"contains":"Gaming Mouse","testid":"item-card"},"testid":"add-to-cart"},{"actor":"partial-shopper","do":"click","in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"add-to-cart"},{"actor":"available-shopper","do":"wait","ms":310000}]},"packId":"ecommerce.progression.cart-recovery","role":"feature","source":"scenarios/progression-cart-recovery.json"}],"id":"selected-source-069","scenario":{"level":5,"writeUrlPattern":null},"source":"scenarios/progression-cart-recovery.json"},{"checkGroups":[{"checkGroupId":"catalog-management","feature":{"actors":["admin","visitor"],"criteria":[{"id":"622a","steps":[{"actor":"visitor","contains":"Travel Mug","do":"expect","testid":"item-card","within":10000}]},{"id":"622b","steps":[{"actor":"visitor","do":"openItem","item":"Travel Mug","unlessVisible":"item-variant"},{"actor":"visitor","contains":"Black","do":"expectElementCount","equals":1,"testid":"item-variant","within":10000},{"actor":"visitor","contains":"Silver","do":"expectElementCount","equals":1,"testid":"item-variant","within":10000}]}],"id":622,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"click","testid":"admin-link"},{"actor":"admin","do":"fill","testid":"catalog-name","text":"Travel Mug"},{"actor":"admin","do":"fill","testid":"catalog-category","text":"Kitchen"},{"actor":"admin","do":"fill","testid":"catalog-price","text":"24.00"},{"actor":"admin","do":"fill","testid":"catalog-variants","text":"Black, Silver"},{"actor":"admin","do":"click","testid":"catalog-save"},{"actor":"visitor","do":"reload","settleMs":2500},{"actor":"visitor","do":"fill","enter":true,"testid":"search-input","text":"Travel Mug"}]},"packId":"ecommerce.progression.catalog-management","role":"feature","source":"scenarios/progression-catalog-management.json"}],"id":"selected-source-070","scenario":{"level":5,"writeUrlPattern":null},"source":"scenarios/progression-catalog-management.json"},{"checkGroups":[{"checkGroupId":"checkout-crash-integrity","feature":{"actors":["a","b","c"],"criteria":[{"id":"910a","steps":[{"do":"expectCrashCheckout","from":"database-crash-observation","verdict":"atomicity"},{"do":"expectCrashCheckout","from":"application-crash-observation","verdict":"atomicity"}]}],"id":910,"setup":[{"actor":"a","do":"signUp","name":"database"},{"account":"{user:database}","as":"database-baseline-before","do":"dbRecordCheckout","item":"Keyboard","storage":{"cart":true,"kind":"order-data","warehouses":false}},{"actor":"a","do":"click","in":{"contains":"Keyboard","testid":"item-card"},"testid":"add-to-cart"},{"account":"{user:database}","as":"database-baseline-prepared","do":"dbRecordCheckout","item":"Keyboard","storage":{"cart":true,"kind":"order-data","warehouses":false}},{"actor":"a","do":"confirmCheckout","namedAction":{"args":[],"id":"checkout","path":"/api/checkout","reducer":"checkout"}},{"before":"database-baseline-before","do":"dbExpectCheckout","prepared":"database-baseline-prepared","quantity":1},{"actor":"a","do":"reload","settleMs":0},{"account":"{user:database}","as":"database-before","do":"dbRecordCheckout","item":"Keyboard","storage":{"cart":true,"kind":"order-data","warehouses":false}},{"actor":"a","do":"click","in":{"contains":"Keyboard","testid":"item-card"},"testid":"add-to-cart"},{"account":"{user:database}","as":"database-prepared","do":"dbRecordCheckout","item":"Keyboard","storage":{"cart":true,"kind":"order-data","warehouses":false}},{"actor":"a","as":"database-crash-observation","before":"database-before","do":"crashCheckout","namedAction":{"args":[],"id":"checkout","path":"/api/checkout","reducer":"checkout"},"offsetMs":0,"prepared":"database-prepared","quantity":1,"requests":16,"target":"database"},{"actor":"b","do":"signUp","name":"application"},{"account":"{user:application}","as":"application-baseline-before","do":"dbRecordCheckout","item":"Keyboard","storage":{"cart":true,"kind":"order-data","warehouses":false}},{"actor":"b","do":"click","in":{"contains":"Keyboard","testid":"item-card"},"testid":"add-to-cart"},{"account":"{user:application}","as":"application-baseline-prepared","do":"dbRecordCheckout","item":"Keyboard","storage":{"cart":true,"kind":"order-data","warehouses":false}},{"actor":"b","do":"confirmCheckout","namedAction":{"args":[],"id":"checkout","path":"/api/checkout","reducer":"checkout"}},{"before":"application-baseline-before","do":"dbExpectCheckout","prepared":"application-baseline-prepared","quantity":1},{"actor":"b","do":"reload","settleMs":0},{"account":"{user:application}","as":"application-before","do":"dbRecordCheckout","item":"Keyboard","storage":{"cart":true,"kind":"order-data","warehouses":false}},{"actor":"b","do":"click","in":{"contains":"Keyboard","testid":"item-card"},"testid":"add-to-cart"},{"account":"{user:application}","as":"application-prepared","do":"dbRecordCheckout","item":"Keyboard","storage":{"cart":true,"kind":"order-data","warehouses":false}},{"actor":"b","as":"application-crash-observation","before":"application-before","do":"crashCheckout","namedAction":{"args":[],"id":"checkout","path":"/api/checkout","reducer":"checkout"},"offsetMs":0,"prepared":"application-prepared","quantity":1,"requests":16,"reuseCombinedFrom":"database-crash-observation","target":"application"},{"actor":"c","do":"signUp","name":"recovered"},{"account":"{user:recovered}","as":"recovered-before","do":"dbRecordCheckout","item":"Keyboard","storage":{"cart":true,"kind":"order-data","warehouses":false}},{"actor":"c","do":"click","in":{"contains":"Keyboard","testid":"item-card"},"testid":"add-to-cart"},{"account":"{user:recovered}","as":"recovered-prepared","do":"dbRecordCheckout","item":"Keyboard","storage":{"cart":true,"kind":"order-data","warehouses":false}},{"actor":"c","do":"click","testid":"cart-toggle"},{"actor":"c","do":"click","testid":"checkout-submit"},{"actor":"c","do":"expectNumber","equals":0,"testid":"cart-count","within":10000},{"actor":"c","do":"click","ifAvailable":true,"testid":"overlay-close"},{"before":"recovered-before","do":"dbExpectCheckout","prepared":"recovered-prepared","quantity":1}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.state-durability","requiresFeatures":["ecommerce.feature.checkout"],"role":"guarantee","source":"scenarios/progression-checkout-crash.json"},{"checkGroupId":"checkout-crash-durability","feature":{"actors":["a","b","c"],"criteria":[{"id":"910b","steps":[{"do":"expectCrashCheckout","from":"database-crash-observation","verdict":"durability"},{"do":"expectCrashCheckout","from":"application-crash-observation","verdict":"durability"}]}],"id":910,"setup":[{"actor":"a","do":"signUp","name":"database"},{"account":"{user:database}","as":"database-baseline-before","do":"dbRecordCheckout","item":"Keyboard","storage":{"cart":true,"kind":"order-data","warehouses":false}},{"actor":"a","do":"click","in":{"contains":"Keyboard","testid":"item-card"},"testid":"add-to-cart"},{"account":"{user:database}","as":"database-baseline-prepared","do":"dbRecordCheckout","item":"Keyboard","storage":{"cart":true,"kind":"order-data","warehouses":false}},{"actor":"a","do":"confirmCheckout","namedAction":{"args":[],"id":"checkout","path":"/api/checkout","reducer":"checkout"}},{"before":"database-baseline-before","do":"dbExpectCheckout","prepared":"database-baseline-prepared","quantity":1},{"actor":"a","do":"reload","settleMs":0},{"account":"{user:database}","as":"database-before","do":"dbRecordCheckout","item":"Keyboard","storage":{"cart":true,"kind":"order-data","warehouses":false}},{"actor":"a","do":"click","in":{"contains":"Keyboard","testid":"item-card"},"testid":"add-to-cart"},{"account":"{user:database}","as":"database-prepared","do":"dbRecordCheckout","item":"Keyboard","storage":{"cart":true,"kind":"order-data","warehouses":false}},{"actor":"a","as":"database-crash-observation","before":"database-before","do":"crashCheckout","namedAction":{"args":[],"id":"checkout","path":"/api/checkout","reducer":"checkout"},"offsetMs":0,"prepared":"database-prepared","quantity":1,"requests":16,"target":"database"},{"actor":"b","do":"signUp","name":"application"},{"account":"{user:application}","as":"application-baseline-before","do":"dbRecordCheckout","item":"Keyboard","storage":{"cart":true,"kind":"order-data","warehouses":false}},{"actor":"b","do":"click","in":{"contains":"Keyboard","testid":"item-card"},"testid":"add-to-cart"},{"account":"{user:application}","as":"application-baseline-prepared","do":"dbRecordCheckout","item":"Keyboard","storage":{"cart":true,"kind":"order-data","warehouses":false}},{"actor":"b","do":"confirmCheckout","namedAction":{"args":[],"id":"checkout","path":"/api/checkout","reducer":"checkout"}},{"before":"application-baseline-before","do":"dbExpectCheckout","prepared":"application-baseline-prepared","quantity":1},{"actor":"b","do":"reload","settleMs":0},{"account":"{user:application}","as":"application-before","do":"dbRecordCheckout","item":"Keyboard","storage":{"cart":true,"kind":"order-data","warehouses":false}},{"actor":"b","do":"click","in":{"contains":"Keyboard","testid":"item-card"},"testid":"add-to-cart"},{"account":"{user:application}","as":"application-prepared","do":"dbRecordCheckout","item":"Keyboard","storage":{"cart":true,"kind":"order-data","warehouses":false}},{"actor":"b","as":"application-crash-observation","before":"application-before","do":"crashCheckout","namedAction":{"args":[],"id":"checkout","path":"/api/checkout","reducer":"checkout"},"offsetMs":0,"prepared":"application-prepared","quantity":1,"requests":16,"reuseCombinedFrom":"database-crash-observation","target":"application"},{"actor":"c","do":"signUp","name":"recovered"},{"account":"{user:recovered}","as":"recovered-before","do":"dbRecordCheckout","item":"Keyboard","storage":{"cart":true,"kind":"order-data","warehouses":false}},{"actor":"c","do":"click","in":{"contains":"Keyboard","testid":"item-card"},"testid":"add-to-cart"},{"account":"{user:recovered}","as":"recovered-prepared","do":"dbRecordCheckout","item":"Keyboard","storage":{"cart":true,"kind":"order-data","warehouses":false}},{"actor":"c","do":"click","testid":"cart-toggle"},{"actor":"c","do":"click","testid":"checkout-submit"},{"actor":"c","do":"expectNumber","equals":0,"testid":"cart-count","within":10000},{"actor":"c","do":"click","ifAvailable":true,"testid":"overlay-close"},{"before":"recovered-before","do":"dbExpectCheckout","prepared":"recovered-prepared","quantity":1}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.state-durability","requiresFeatures":["ecommerce.feature.checkout"],"role":"guarantee","source":"scenarios/progression-checkout-crash.json"}],"id":"selected-source-071","scenario":{"level":1,"writeUrlPattern":null},"source":"scenarios/progression-checkout-crash.json"},{"checkGroups":[{"checkGroupId":"payment-records","feature":{"actors":["tab1","tab2","owner"],"criteria":[{"id":"623a","steps":[{"actor":"owner-fresh","do":"expect","ignoreCase":true,"in":{"contains":"Desk Lamp","testid":"order-item"},"testid":"payment-status","value":"paid","within":10000},{"actor":"owner-fresh","do":"expectNumber","in":{"contains":"Desk Lamp","testid":"order-item"},"plus":0,"relativeTo":"payment-total","testid":"payment-amount"}]}],"id":623,"setup":[{"actor":"tab1","do":"signUp","name":"payment-record"},{"actor":"tab2","do":"signIn","name":"payment-record"},{"actor":"owner","do":"signIn","name":"payment-record"},{"actor":"owner","do":"click","in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"add-to-cart"},{"actor":"owner","do":"click","testid":"cart-toggle"},{"actor":"owner","as":"payment-total","do":"recordNumber","testid":"cart-total"},{"action":"checkout","actors":["tab1","tab2"],"do":"callConcurrently","settleMs":5000},{"do":"expectCallOutcomes"},{"actor":"owner","do":"freshClient"},{"actor":"owner-fresh","do":"signIn","name":"payment-record"},{"actor":"owner-fresh","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"owner-fresh","do":"click","testid":"orders-toggle"},{"actor":"owner-fresh","contains":"Desk Lamp","do":"expectElementCount","equals":1,"testid":"order-item","within":10000}]},"packId":"ecommerce.progression.payment-records","role":"feature","source":"scenarios/progression-core-business.json"},{"checkGroupId":"payment-deduplication","feature":{"actors":["tab1","tab2","owner"],"criteria":[{"id":"623b","steps":[{"actor":"owner-fresh","do":"expectElementCount","equals":1,"in":{"contains":"Desk Lamp","testid":"order-item"},"testid":"payment-record","within":10000}]}],"id":623,"setup":[{"actor":"tab1","do":"signUp","name":"payment-record"},{"actor":"tab2","do":"signIn","name":"payment-record"},{"actor":"owner","do":"signIn","name":"payment-record"},{"actor":"owner","do":"click","in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"add-to-cart"},{"actor":"owner","do":"click","testid":"cart-toggle"},{"actor":"owner","as":"payment-total","do":"recordNumber","testid":"cart-total"},{"action":"checkout","actors":["tab1","tab2"],"do":"callConcurrently","settleMs":5000},{"do":"expectCallOutcomes"},{"actor":"owner","do":"freshClient"},{"actor":"owner-fresh","do":"signIn","name":"payment-record"},{"actor":"owner-fresh","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"owner-fresh","do":"click","testid":"orders-toggle"},{"actor":"owner-fresh","contains":"Desk Lamp","do":"expectElementCount","equals":1,"testid":"order-item","within":10000}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.transactional-integrity","requiresFeatures":["ecommerce.progression.payment-records"],"role":"guarantee","source":"scenarios/progression-core-business.json"}],"id":"selected-source-072","scenario":{"level":5,"writeUrlPattern":null},"source":"scenarios/progression-core-business.json"},{"checkGroups":[{"checkGroupId":"customer-profile","feature":{"actors":["owner","privateOwner","other"],"criteria":[{"id":"620c","steps":[{"actor":"owner","do":"click","ifAvailable":true,"testid":"overlay-close"},{"actor":"owner","do":"click","ifAvailable":true,"testid":"catalog-link"},{"actor":"owner","do":"click","testid":"profile-link","unlessVisible":"profile-address-summary"},{"actor":"owner","contains":"14 Market Street {user:profilemarker}","do":"expect","testid":"profile-address-summary"}]}],"id":620,"setup":[{"actor":"owner","do":"signUp","name":"profile-owner"},{"actor":"owner","do":"click","testid":"profile-link"},{"actor":"owner","do":"fill","testid":"profile-name","text":"Avery Stone"},{"actor":"owner","do":"fill","testid":"profile-address","text":"14 Market Street {user:profilemarker}"},{"actor":"owner","do":"click","testid":"profile-save"}]},"packId":"ecommerce.progression.customer-profile","role":"feature","source":"scenarios/progression-customer-profile.json"},{"checkGroupId":"customer-profile-reload","feature":{"actors":["owner","privateOwner","other"],"criteria":[{"id":"620a","steps":[{"actor":"owner","do":"reload","settleMs":2500},{"actor":"owner","do":"ensureSignedIn","name":"profile-owner","readyTestid":"current-user"},{"actor":"owner","do":"click","testid":"profile-link"},{"actor":"owner","contains":"14 Market Street {user:profilemarker}","do":"expect","testid":"profile-address-summary"},{"do":"restartBackend","settleMs":1000},{"actor":"owner","do":"freshClient"},{"actor":"owner-fresh","do":"signIn","name":"profile-owner"},{"actor":"owner-fresh","do":"click","testid":"profile-link"},{"actor":"owner-fresh","contains":"14 Market Street {user:profilemarker}","do":"expect","testid":"profile-address-summary"}]}],"id":620,"setup":[{"actor":"owner","do":"signUp","name":"profile-owner"},{"actor":"owner","do":"click","testid":"profile-link"},{"actor":"owner","do":"fill","testid":"profile-name","text":"Avery Stone"},{"actor":"owner","do":"fill","testid":"profile-address","text":"14 Market Street {user:profilemarker}"},{"actor":"owner","do":"click","testid":"profile-save"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.state-durability","requiresFeatures":["ecommerce.progression.customer-profile"],"role":"guarantee","source":"scenarios/progression-customer-profile.json"},{"checkGroupId":"customer-profile-privacy","feature":{"actors":["owner","privateOwner","other"],"criteria":[{"id":"620b","steps":[{"actor":"privateOwner","do":"reload","settleMs":0},{"actor":"privateOwner","do":"signUp","name":"profile-private-owner"},{"actor":"privateOwner","do":"click","testid":"profile-link"},{"actor":"privateOwner","do":"fill","testid":"profile-name","text":"Avery Stone"},{"actor":"privateOwner","do":"fill","testid":"profile-address","text":"14 Market Street {user:profilemarker}"},{"actor":"privateOwner","do":"click","testid":"profile-save"},{"actor":"privateOwner","do":"reload","settleMs":1000},{"actor":"privateOwner","do":"ensureSignedIn","name":"profile-private-owner","readyTestid":"current-user"},{"actor":"privateOwner","do":"click","testid":"profile-link"},{"actor":"privateOwner","contains":"14 Market Street {user:profilemarker}","do":"expect","testid":"profile-address-summary"},{"actor":"privateOwner","contains":"14 Market Street {user:profilemarker}","do":"expectReceived","within":10000},{"actor":"other","do":"reload","settleMs":0},{"actor":"other","do":"signUp","name":"profile-other"},{"actor":"other","do":"click","testid":"profile-link"},{"absent":true,"actor":"other","contains":"14 Market Street {user:profilemarker}","do":"expect","testid":"profile-address-summary"},{"actor":"other","contains":"14 Market Street {user:profilemarker}","do":"expectNotReceived"}]}],"id":620,"setup":[{"actor":"owner","do":"signUp","name":"profile-owner"},{"actor":"owner","do":"click","testid":"profile-link"},{"actor":"owner","do":"fill","testid":"profile-name","text":"Avery Stone"},{"actor":"owner","do":"fill","testid":"profile-address","text":"14 Market Street {user:profilemarker}"},{"actor":"owner","do":"click","testid":"profile-save"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","requiresFeatures":["ecommerce.progression.customer-profile"],"role":"guarantee","source":"scenarios/progression-customer-profile.json"}],"id":"selected-source-073","scenario":{"level":2,"writeUrlPattern":null},"source":"scenarios/progression-customer-profile.json"},{"checkGroups":[{"checkGroupId":"delivery-notification-delivery","feature":{"actors":["owner","other","staff"],"criteria":[{"id":"501a","steps":[{"actor":"owner","do":"reload","settleMs":1000},{"actor":"owner","do":"ensureSignedIn","name":"delivery-owner","readyTestid":"current-user"},{"actor":"owner","do":"click","testid":"notifications-toggle","unlessVisible":"notifications-panel"},{"actor":"owner","attribute":"aria-busy","do":"expect","testid":"notifications-panel","value":"false","within":10000},{"actor":"owner","contains":"Desk Lamp","do":"expectElementCount","equals":1,"testid":"notification-item","within":10000}]}],"id":501,"setup":[{"actor":"owner","do":"signUp","name":"delivery-owner"},{"actor":"other","do":"signUp","name":"delivery-other"},{"actor":"owner","do":"click","testid":"notification-settings","unlessVisible":"notification-order"},{"actor":"owner","do":"click","testid":"notification-order"},{"actor":"owner","do":"click","testid":"notification-save"},{"actor":"owner","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"owner","do":"click","testid":"catalog-link"},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"action":"buy","actor":"owner","do":"callAction","input":{"attribute":"data-buy-input","contains":"Desk Lamp","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"}},{"actor":"owner","do":"expectActionOutcome","outcome":"accepted"},{"actor":"owner","do":"reload","settleMs":1000},{"actor":"owner","do":"ensureSignedIn","name":"delivery-owner","readyTestid":"current-user"},{"actor":"owner","do":"click","testid":"notifications-toggle","unlessVisible":"notifications-panel"},{"actor":"owner","attribute":"aria-busy","do":"expect","testid":"notifications-panel","value":"false","within":10000},{"actor":"owner","contains":"Desk Lamp","do":"expectElementCount","equals":0,"testid":"notification-item"},{"actor":"owner","do":"reload","settleMs":1000},{"actor":"owner","do":"ensureSignedIn","name":"delivery-owner","readyTestid":"current-user"},{"actor":"owner","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"owner","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"as":"notification-shipped","do":"recordTime"},{"action":"ship","actor":"staff","do":"callAction","from":"owner","input":{"attribute":"data-ship-input","contains":"Desk Lamp","testid":"order-item"},"namedAction":{"args":[0],"id":"ship","params":[{"in":"body","name":"orderId","wireType":"u64"}],"path":"/api/fulfilment/ship","reducer":"ship_order"}},{"actor":"staff","do":"expectActionOutcome","outcome":"accepted"},{"as":"notification-shipped-accepted","do":"recordTime"},{"actor":"owner","do":"reload","settleMs":1000},{"actor":"owner","do":"ensureSignedIn","name":"delivery-owner","readyTestid":"current-user"},{"actor":"owner","do":"click","testid":"notifications-toggle","unlessVisible":"notifications-panel"},{"actor":"owner","attribute":"aria-busy","do":"expect","testid":"notifications-panel","value":"false","within":10000},{"atMost":40000,"do":"expectElapsed","since":"notification-shipped"},{"actor":"owner","contains":"Desk Lamp","do":"expectElementCount","equals":0,"testid":"notification-item"},{"actor":"owner","do":"wait","ms":75000,"since":"notification-shipped-accepted"},{"actor":"owner","do":"reload","settleMs":1000},{"actor":"owner","do":"ensureSignedIn","name":"delivery-owner","readyTestid":"current-user"},{"actor":"owner","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"owner","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"owner","do":"expect","ignoreCase":true,"in":{"contains":"Desk Lamp","testid":"order-item"},"testid":"order-status","value":"delivered"}]},"packId":"ecommerce.progression.delivery-notifications","requiresFeatures":["ecommerce.feature.purchasing","ecommerce.progression.fulfilment-queue"],"role":"feature","source":"scenarios/progression-delivery-notifications.json"},{"checkGroupId":"delivery-notification-privacy","feature":{"actors":["owner","other","staff"],"criteria":[{"id":"501b","steps":[{"actor":"owner","do":"reload","settleMs":1000},{"actor":"owner","do":"ensureSignedIn","name":"delivery-owner","readyTestid":"current-user"},{"actor":"owner","do":"click","testid":"notifications-toggle","unlessVisible":"notifications-panel"},{"actor":"owner","contains":"Desk Lamp","do":"expectElementCount","equals":1,"testid":"notification-item","within":10000},{"actor":"other","do":"click","testid":"notifications-toggle","unlessVisible":"notifications-panel"},{"actor":"other","attribute":"aria-busy","do":"expect","testid":"notifications-panel","value":"false","within":10000},{"absent":true,"actor":"other","contains":"Desk Lamp","do":"expect","testid":"notification-item"}]}],"id":501,"setup":[{"actor":"owner","do":"signUp","name":"delivery-owner"},{"actor":"other","do":"signUp","name":"delivery-other"},{"actor":"owner","do":"click","testid":"notification-settings","unlessVisible":"notification-order"},{"actor":"owner","do":"click","testid":"notification-order"},{"actor":"owner","do":"click","testid":"notification-save"},{"actor":"owner","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"owner","do":"click","testid":"catalog-link"},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"action":"buy","actor":"owner","do":"callAction","input":{"attribute":"data-buy-input","contains":"Desk Lamp","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"}},{"actor":"owner","do":"expectActionOutcome","outcome":"accepted"},{"actor":"owner","do":"reload","settleMs":1000},{"actor":"owner","do":"ensureSignedIn","name":"delivery-owner","readyTestid":"current-user"},{"actor":"owner","do":"click","testid":"notifications-toggle","unlessVisible":"notifications-panel"},{"actor":"owner","attribute":"aria-busy","do":"expect","testid":"notifications-panel","value":"false","within":10000},{"actor":"owner","contains":"Desk Lamp","do":"expectElementCount","equals":0,"testid":"notification-item"},{"actor":"owner","do":"reload","settleMs":1000},{"actor":"owner","do":"ensureSignedIn","name":"delivery-owner","readyTestid":"current-user"},{"actor":"owner","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"owner","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"as":"notification-shipped","do":"recordTime"},{"action":"ship","actor":"staff","do":"callAction","from":"owner","input":{"attribute":"data-ship-input","contains":"Desk Lamp","testid":"order-item"},"namedAction":{"args":[0],"id":"ship","params":[{"in":"body","name":"orderId","wireType":"u64"}],"path":"/api/fulfilment/ship","reducer":"ship_order"}},{"actor":"staff","do":"expectActionOutcome","outcome":"accepted"},{"as":"notification-shipped-accepted","do":"recordTime"},{"actor":"owner","do":"reload","settleMs":1000},{"actor":"owner","do":"ensureSignedIn","name":"delivery-owner","readyTestid":"current-user"},{"actor":"owner","do":"click","testid":"notifications-toggle","unlessVisible":"notifications-panel"},{"actor":"owner","attribute":"aria-busy","do":"expect","testid":"notifications-panel","value":"false","within":10000},{"atMost":40000,"do":"expectElapsed","since":"notification-shipped"},{"actor":"owner","contains":"Desk Lamp","do":"expectElementCount","equals":0,"testid":"notification-item"},{"actor":"owner","do":"wait","ms":75000,"since":"notification-shipped-accepted"},{"actor":"owner","do":"reload","settleMs":1000},{"actor":"owner","do":"ensureSignedIn","name":"delivery-owner","readyTestid":"current-user"},{"actor":"owner","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"owner","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"owner","do":"expect","ignoreCase":true,"in":{"contains":"Desk Lamp","testid":"order-item"},"testid":"order-status","value":"delivered"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","requiresFeatures":["ecommerce.feature.purchasing","ecommerce.progression.delivery-notifications","ecommerce.progression.fulfilment-queue"],"role":"guarantee","source":"scenarios/progression-delivery-notifications.json"}],"id":"selected-source-074","scenario":{"level":5,"writeUrlPattern":null},"source":"scenarios/progression-delivery-notifications.json"},{"checkGroups":[{"checkGroupId":"faceted-search","feature":{"actors":["visitor"],"criteria":[{"id":"401a","steps":[{"actor":"visitor","contains":"Coffee Grinder","do":"expectElementCount","equals":1,"in":{"testid":"search-results"},"testid":"item-card","within":10000},{"actor":"visitor","do":"click","testid":"in-stock-filter"},{"actor":"visitor","do":"click","ifAvailable":true,"testid":"filter-apply"},{"actor":"visitor","contains":"Coffee Grinder","do":"waitUntilAbsent","in":{"testid":"search-results"},"testid":"item-card","within":10000},{"actor":"visitor","contains":"Air Purifier","do":"expectElementCount","equals":1,"in":{"testid":"search-results"},"testid":"item-card"},{"absent":true,"actor":"visitor","contains":"USB Cable","do":"expect","in":{"testid":"search-results"},"testid":"item-card"},{"absent":true,"actor":"visitor","contains":"Desk Lamp","do":"expect","in":{"testid":"search-results"},"testid":"item-card"},{"absent":true,"actor":"visitor","contains":"Espresso Machine","do":"expect","in":{"testid":"search-results"},"testid":"item-card"},{"absent":true,"actor":"visitor","contains":"Gaming Mouse","do":"expect","in":{"testid":"search-results"},"testid":"item-card"}]}],"id":401,"setup":[{"do":"dbSetStock","item":"Coffee Grinder","quantity":0,"settleMs":0,"warehouse":"East"},{"do":"dbSetStock","item":"Coffee Grinder","quantity":0,"settleMs":1000,"warehouse":"West"},{"actor":"visitor","do":"reload","settleMs":1000},{"actor":"visitor","do":"fill","testid":"category-filter","text":"Home"},{"actor":"visitor","do":"fill","testid":"minimum-price","text":"50"},{"actor":"visitor","do":"fill","testid":"maximum-price","text":"200"},{"actor":"visitor","do":"click","ifAvailable":true,"testid":"filter-apply"}]},"packId":"ecommerce.progression.faceted-search","role":"feature","source":"scenarios/progression-faceted-filters.json"}],"id":"selected-source-075","scenario":{"level":3,"writeUrlPattern":null},"source":"scenarios/progression-faceted-filters.json"},{"checkGroups":[{"checkGroupId":"faceted-search","feature":{"actors":["visitor"],"criteria":[{"id":"402a","steps":[{"actor":"visitor","do":"expectSequence","equals":["Air Purifier","Bluetooth Speaker","Coffee Grinder","Desk Lamp","Espresso Machine","Gaming Mouse","Headphones","Induction Cooktop","Keyboard","Laptop Stand"],"in":{"testid":"search-results"},"testid":"item-name"},{"actor":"visitor","do":"click","testid":"search-next-page"},{"actor":"visitor","do":"expectSequence","equals":["Mirrorless Camera","USB Cable","Webcam"],"in":{"testid":"search-results"},"testid":"item-name"},{"actor":"visitor","do":"click","testid":"search-previous-page"},{"actor":"visitor","do":"expectSequence","equals":["Air Purifier","Bluetooth Speaker","Coffee Grinder","Desk Lamp","Espresso Machine","Gaming Mouse","Headphones","Induction Cooktop","Keyboard","Laptop Stand"],"in":{"testid":"search-results"},"testid":"item-name"}]}],"id":402,"setup":[{"actor":"visitor","do":"fill","testid":"minimum-price","text":"1"},{"actor":"visitor","do":"click","ifAvailable":true,"testid":"filter-apply"}]},"packId":"ecommerce.progression.faceted-search","role":"feature","source":"scenarios/progression-faceted-pagination.json"}],"id":"selected-source-076","scenario":{"level":3,"writeUrlPattern":null},"source":"scenarios/progression-faceted-pagination.json"},{"checkGroups":[{"checkGroupId":"managed-support-privacy","feature":{"actors":["owner","other","staff"],"criteria":[{"id":"613b","steps":[{"actor":"owner","do":"reload","settleMs":1000},{"actor":"owner","do":"ensureSignedIn","name":"managed-private-owner","readyTestid":"current-user"},{"actor":"owner","do":"click","testid":"support-link"},{"actor":"owner","contains":"Private managed case {user:casemarker}","do":"expect","testid":"support-ticket"},{"actor":"owner","contains":"Private managed case {user:casemarker}","do":"expectReceived","within":10000},{"absent":true,"actor":"other","contains":"Private managed case {user:casemarker}","do":"expect","testid":"support-ticket"},{"actor":"other","contains":"Private managed case {user:casemarker}","do":"expectNotReceived"},{"actor":"owner","do":"fill","in":{"contains":"Private managed case {user:casemarker}","testid":"support-ticket"},"testid":"support-reply","text":"Owner-only update"},{"actor":"owner","do":"click","in":{"contains":"Private managed case {user:casemarker}","testid":"support-ticket"},"testid":"support-reply-submit"},{"actor":"other","do":"replayAs","from":"owner","match":"Owner-only update","namedAction":{"args":[0,"Owner-only update"],"id":"replySupport","method":"POST","params":[{"in":"path","name":"ticketId","placeholder":":id","wireType":"u64"},{"in":"body","name":"body"}],"path":"/api/support/:id/replies","reducer":"reply_support"},"namedTarget":{"attribute":"data-entity-id","contains":"Private managed case {user:casemarker}","testid":"support-ticket","valueType":"string"},"settleMs":1500},{"actor":"other","allowNotFound":true,"do":"expectReplayRejected"},{"actor":"staff","do":"reload","settleMs":2000},{"actor":"staff","do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026","readyTestid":"current-user"},{"actor":"staff","do":"click","ifAvailable":true,"testid":"staff-link","unlessVisible":"support-assignee"},{"actor":"staff","do":"click","ifAvailable":true,"testid":"support-queue-link","unlessVisible":"support-assignee"},{"actor":"staff","contains":"Private managed case {user:casemarker}","do":"expect","testid":"support-ticket"},{"actor":"staff","contains":"Owner-only update","do":"expectElementCount","equals":1,"testid":"support-reply-item","within":10000},{"actor":"staff","contains":"Owner-only update","do":"expectReceived","within":10000},{"actor":"other","contains":"Owner-only update","do":"expectNotReceived"}]}],"id":613,"setup":[{"actor":"owner","do":"signUp","name":"managed-private-owner"},{"actor":"owner","do":"click","testid":"support-link"},{"actor":"owner","do":"fill","testid":"support-email","text":"managed-private@example.com"},{"actor":"owner","do":"fill","testid":"support-subject","text":"Private managed case {user:casemarker}"},{"actor":"owner","do":"fill","testid":"support-message","text":"Private case details."},{"actor":"owner","do":"click","testid":"support-submit"},{"actor":"owner","do":"expect","nonEmpty":true,"testid":"support-reference"},{"actor":"other","do":"signUp","name":"managed-private-other"},{"actor":"other","do":"click","testid":"support-link"},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"staff","do":"click","testid":"staff-link","unlessVisible":"support-assignee"},{"actor":"staff","do":"click","ifAvailable":true,"testid":"support-queue-link","unlessVisible":"support-assignee"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","requiresFeatures":["ecommerce.progression.managed-support"],"role":"guarantee","source":"scenarios/progression-managed-support-privacy.json"}],"id":"selected-source-077","scenario":{"level":3,"writeUrlPattern":null},"source":"scenarios/progression-managed-support-privacy.json"},{"checkGroups":[{"checkGroupId":"managed-support","feature":{"actors":["owner","staff"],"criteria":[{"id":"613c","steps":[{"actor":"staff","do":"fill","in":{"contains":"Shared managed case","testid":"support-ticket"},"testid":"support-status-input","text":"in progress"},{"actor":"staff","do":"click","in":{"contains":"Shared managed case","testid":"support-ticket"},"settleMs":1500,"testid":"support-update"},{"actor":"staff","do":"fill","in":{"contains":"Shared managed case","testid":"support-ticket"},"testid":"support-reply","text":"Case received."},{"actor":"staff","do":"click","in":{"contains":"Shared managed case","testid":"support-ticket"},"testid":"support-reply-submit"},{"actor":"owner","do":"reload","settleMs":2000},{"actor":"owner","do":"ensureSignedIn","name":"managed-shared-owner","readyTestid":"current-user"},{"actor":"owner","do":"click","testid":"support-link"},{"actor":"owner","contains":"in progress","do":"expect","in":{"contains":"Shared managed case","testid":"support-ticket"},"testid":"support-status"},{"actor":"owner","contains":"Case received.","do":"expect","in":{"contains":"Shared managed case","testid":"support-ticket"},"testid":"support-reply-item"},{"actor":"owner","do":"fill","in":{"contains":"Shared managed case","testid":"support-ticket"},"testid":"support-reply","text":"Thank you."},{"actor":"owner","do":"click","in":{"contains":"Shared managed case","testid":"support-ticket"},"testid":"support-reply-submit"},{"actor":"staff","do":"reload","settleMs":2000},{"actor":"staff","do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026","readyTestid":"current-user"},{"actor":"staff","do":"click","testid":"staff-link","unlessVisible":"support-assignee"},{"actor":"staff","do":"click","ifAvailable":true,"testid":"support-queue-link","unlessVisible":"support-assignee"},{"actor":"staff","contains":"Thank you.","do":"expect","in":{"contains":"Shared managed case","testid":"support-ticket"},"testid":"support-reply-item"}]}],"id":613,"setup":[{"actor":"owner","do":"signUp","name":"managed-shared-owner"},{"actor":"owner","do":"click","testid":"support-link"},{"actor":"owner","do":"fill","testid":"support-email","text":"managed-shared@example.com"},{"actor":"owner","do":"fill","testid":"support-subject","text":"Shared managed case"},{"actor":"owner","do":"fill","testid":"support-message","text":"Please investigate this case."},{"actor":"owner","do":"click","testid":"support-submit"},{"actor":"owner","do":"expect","nonEmpty":true,"testid":"support-reference"},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"staff","do":"click","testid":"staff-link","unlessVisible":"support-assignee"},{"actor":"staff","do":"click","ifAvailable":true,"testid":"support-queue-link","unlessVisible":"support-assignee"}]},"packId":"ecommerce.progression.managed-support","role":"feature","source":"scenarios/progression-managed-support-shared.json"},{"checkGroupId":"managed-support","feature":{"actors":["owner","staff"],"criteria":[{"id":"613a","steps":[{"actor":"staff","do":"fill","in":{"contains":"Shared managed case","testid":"support-ticket"},"testid":"support-status-input","text":"open"},{"actor":"staff","do":"click","in":{"contains":"Shared managed case","testid":"support-ticket"},"testid":"support-update"},{"actor":"staff","contains":"open","do":"expect","in":{"contains":"Shared managed case","testid":"support-ticket"},"testid":"support-status"},{"actor":"owner","do":"reload","settleMs":1000},{"actor":"owner","do":"ensureSignedIn","name":"managed-shared-owner","readyTestid":"current-user"},{"actor":"owner","do":"click","testid":"support-link","unlessVisible":"support-ticket"},{"actor":"owner","contains":"open","do":"expect","in":{"contains":"Shared managed case","testid":"support-ticket"},"testid":"support-status"},{"actor":"staff","do":"fill","in":{"contains":"Shared managed case","testid":"support-ticket"},"testid":"support-status-input","text":"in progress"},{"actor":"staff","do":"click","in":{"contains":"Shared managed case","testid":"support-ticket"},"settleMs":1500,"testid":"support-update"},{"actor":"staff","do":"fill","in":{"contains":"Shared managed case","testid":"support-ticket"},"testid":"support-reply","text":"We are investigating."},{"actor":"staff","do":"click","in":{"contains":"Shared managed case","testid":"support-ticket"},"testid":"support-reply-submit"},{"actor":"owner","contains":"in progress","do":"expect","in":{"contains":"Shared managed case","testid":"support-ticket"},"testid":"support-status","within":10000},{"actor":"owner","contains":"We are investigating.","do":"expect","in":{"contains":"Shared managed case","testid":"support-ticket"},"testid":"support-reply-item","within":10000},{"actor":"owner","do":"fill","in":{"contains":"Shared managed case","testid":"support-ticket"},"testid":"support-reply","text":"Thank you for the update."},{"actor":"owner","do":"click","in":{"contains":"Shared managed case","testid":"support-ticket"},"testid":"support-reply-submit"},{"actor":"staff","contains":"Thank you for the update.","do":"expect","in":{"contains":"Shared managed case","testid":"support-ticket"},"testid":"support-reply-item","within":10000}]}],"id":613,"setup":[{"actor":"owner","do":"signUp","name":"managed-shared-owner"},{"actor":"owner","do":"click","testid":"support-link"},{"actor":"owner","do":"fill","testid":"support-email","text":"managed-shared@example.com"},{"actor":"owner","do":"fill","testid":"support-subject","text":"Shared managed case"},{"actor":"owner","do":"fill","testid":"support-message","text":"Please investigate this case."},{"actor":"owner","do":"click","testid":"support-submit"},{"actor":"owner","do":"expect","nonEmpty":true,"testid":"support-reference"},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"staff","do":"click","testid":"staff-link","unlessVisible":"support-assignee"},{"actor":"staff","do":"click","ifAvailable":true,"testid":"support-queue-link","unlessVisible":"support-assignee"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.live-state","requiresFeatures":["ecommerce.progression.managed-support"],"role":"guarantee","source":"scenarios/progression-managed-support-shared.json"}],"id":"selected-source-078","scenario":{"level":3,"writeUrlPattern":null},"source":"scenarios/progression-managed-support-shared.json"},{"checkGroups":[{"checkGroupId":"notification-preferences","feature":{"actors":["owner","other"],"criteria":[{"id":"630c","steps":[{"actor":"owner","do":"click","ifAvailable":true,"testid":"overlay-close"},{"actor":"owner","do":"click","ifAvailable":true,"testid":"catalog-link"},{"actor":"owner","do":"click","testid":"notification-settings","unlessVisible":"notification-order"},{"actor":"owner","attribute":"data-state","do":"expect","testid":"notification-order","value":"on"}]}],"id":630,"setup":[{"actor":"owner","do":"signUp","name":"notification-owner"},{"actor":"other","do":"signUp","name":"notification-other"},{"actor":"owner","do":"click","testid":"notification-settings","unlessVisible":"notification-order"},{"actor":"owner","do":"click","testid":"notification-order"},{"actor":"owner","do":"click","testid":"notification-save"}]},"packId":"ecommerce.progression.notification-preferences","role":"feature","source":"scenarios/progression-notification-preferences.json"},{"checkGroupId":"notification-preferences-reload","feature":{"actors":["owner","other"],"criteria":[{"id":"630a","steps":[{"actor":"owner","do":"reload","settleMs":3000},{"actor":"owner","do":"ensureSignedIn","name":"notification-owner","readyTestid":"current-user"},{"actor":"owner","do":"click","testid":"notification-settings","unlessVisible":"notification-order"},{"actor":"owner","attribute":"data-state","do":"expect","testid":"notification-order","value":"on"},{"do":"restartBackend","settleMs":1000},{"actor":"owner","do":"freshClient"},{"actor":"owner-fresh","do":"signIn","name":"notification-owner"},{"actor":"owner-fresh","do":"click","testid":"notification-settings","unlessVisible":"notification-order"},{"actor":"owner-fresh","attribute":"data-state","do":"expect","testid":"notification-order","value":"on"}]}],"id":630,"setup":[{"actor":"owner","do":"signUp","name":"notification-owner"},{"actor":"other","do":"signUp","name":"notification-other"},{"actor":"owner","do":"click","testid":"notification-settings","unlessVisible":"notification-order"},{"actor":"owner","do":"click","testid":"notification-order"},{"actor":"owner","do":"click","testid":"notification-save"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.state-durability","requiresFeatures":["ecommerce.progression.notification-preferences"],"role":"guarantee","source":"scenarios/progression-notification-preferences.json"},{"checkGroupId":"notification-preferences-privacy","feature":{"actors":["owner","other"],"criteria":[{"id":"630b","steps":[{"actor":"other","do":"click","testid":"notification-settings","unlessVisible":"notification-order"},{"actor":"other","attribute":"data-state","do":"expect","testid":"notification-order","value":"off"}]}],"id":630,"setup":[{"actor":"owner","do":"signUp","name":"notification-owner"},{"actor":"other","do":"signUp","name":"notification-other"},{"actor":"owner","do":"click","testid":"notification-settings","unlessVisible":"notification-order"},{"actor":"owner","do":"click","testid":"notification-order"},{"actor":"owner","do":"click","testid":"notification-save"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","requiresFeatures":["ecommerce.progression.notification-preferences"],"role":"guarantee","source":"scenarios/progression-notification-preferences.json"}],"id":"selected-source-079","scenario":{"level":5,"writeUrlPattern":null},"source":"scenarios/progression-notification-preferences.json"},{"checkGroups":[{"checkGroupId":"open-list","feature":{"actors":["reader","reviewer"],"criteria":[{"id":"902a","steps":[{"actor":"reader","do":"openItem","item":"Keyboard"},{"actor":"reader","do":"expect","testid":"item-detail","within":10000},{"actor":"reviewer","do":"click","ifAvailable":true,"testid":"review-toggle","unlessVisible":"review-rating"},{"actor":"reviewer","do":"fill","testid":"review-input","text":"live-review-kbd"},{"actor":"reviewer","do":"click","testid":"review-submit"},{"actor":"reviewer","contains":"live-review-kbd","do":"expectElementCount","equals":1,"testid":"review-item","within":10000},{"actor":"reader","contains":"live-review-kbd","do":"expectElementCount","equals":1,"testid":"review-item","within":10000}]}],"id":902,"setup":[{"actor":"reviewer","do":"signUp","name":"raceR"},{"actor":"reader","do":"signUp","name":"raceL"},{"action":"buy","actor":"reviewer","do":"callAction","input":{"attribute":"data-buy-input","contains":"Keyboard","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"}},{"actor":"reviewer","do":"expectActionOutcome","outcome":"accepted"},{"actor":"reviewer","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"reviewer","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"reviewer","contains":"Keyboard","do":"expect","testid":"order-item","within":10000},{"actor":"reviewer","do":"click","ifAvailable":true,"testid":"overlay-close"},{"actor":"reviewer","do":"click","ifAvailable":true,"testid":"catalog-link"},{"actor":"reviewer","do":"openItem","item":"Keyboard"},{"actor":"reviewer","do":"expect","testid":"item-detail","within":10000},{"actor":"reviewer","do":"click","ifAvailable":true,"testid":"review-toggle","unlessVisible":"review-rating"},{"actor":"reviewer","do":"fill","testid":"review-rating","text":"5"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.live-state","requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.reviews"],"role":"guarantee","source":"scenarios/progression-open-list-live.json"}],"id":"selected-source-080","scenario":{"level":1,"writeUrlPattern":null},"source":"scenarios/progression-open-list-live.json"},{"checkGroups":[{"checkGroupId":"cancellation-and-return","feature":{"actors":["customer"],"criteria":[{"id":"3e","steps":[{"absent":true,"actor":"customer","do":"expect","in":{"contains":"Desk Lamp","testid":"order-item"},"testid":"return-item"}]}],"id":331,"setup":[{"actor":"customer","do":"signUp","name":"return-boundary"},{"action":"buy","actor":"customer","do":"callAction","input":{"attribute":"data-buy-input","contains":"Desk Lamp","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"}},{"actor":"customer","do":"expectActionOutcome","outcome":"accepted"},{"actor":"customer","do":"reload","settleMs":1000},{"actor":"customer","do":"ensureSignedIn","name":"return-boundary","readyTestid":"current-user"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"customer","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"customer","do":"expect","ignoreCase":true,"in":{"contains":"Desk Lamp","testid":"order-item"},"testid":"order-status","value":"pending"}]},"packId":"ecommerce.l3.order-returns-features","requiresFeatures":["ecommerce.feature.purchasing","ecommerce.progression.fulfilment-queue"],"role":"feature","source":"scenarios/progression-order-return-boundary.json","stablePackId":"ecommerce.returns-pricing"},{"checkGroupId":"cancellation-and-return","feature":{"actors":["customer","staff","admin"],"criteria":[{"id":"3f","steps":[{"action":"returnItem","actor":"customer","do":"callAction","input":{"attribute":"data-return-input","contains":"Desk Lamp","testid":"order-line"},"namedAction":{"args":[0,0],"id":"returnItem","method":"POST","params":[{"in":"path","name":"orderId","placeholder":"{orderId}","wireType":"u64"},{"in":"path","name":"itemId","placeholder":"{itemId}","wireType":"u64"}],"path":"/api/orders/{orderId}/items/{itemId}/return","reducer":"return_order_item"}},{"actor":"customer","do":"expectActionOutcome","outcome":"validation-refused"},{"actor":"customer","do":"reload","settleMs":1000},{"actor":"customer","do":"ensureSignedIn","name":"return-boundary","readyTestid":"current-user"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"customer","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"customer","do":"expect","ignoreCase":true,"in":{"contains":"Desk Lamp","testid":"order-item"},"testid":"order-status","value":"pending"},{"do":"dbExpectStock","item":"Desk Lamp","plus":0,"relativeTo":"pending-East","warehouse":"East"},{"do":"dbExpectStock","item":"Desk Lamp","plus":0,"relativeTo":"pending-West","warehouse":"West"},{"actor":"admin","do":"reload","settleMs":1000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"admin","do":"click","testid":"admin-link","unlessVisible":"admin-revenue"},{"actor":"admin","do":"expectNumber","plus":0,"relativeTo":"pending-revenue","testid":"admin-revenue"}]}],"id":332,"setup":[{"actor":"customer","do":"signUp","name":"return-boundary"},{"action":"buy","actor":"customer","do":"callAction","input":{"attribute":"data-buy-input","contains":"Desk Lamp","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"}},{"actor":"customer","do":"expectActionOutcome","outcome":"accepted"},{"actor":"customer","do":"reload","settleMs":1000},{"actor":"customer","do":"ensureSignedIn","name":"return-boundary","readyTestid":"current-user"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"customer","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"customer","do":"expect","ignoreCase":true,"in":{"contains":"Desk Lamp","testid":"order-item"},"testid":"order-status","value":"pending"},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"customer","do":"reload","settleMs":1000},{"actor":"customer","do":"ensureSignedIn","name":"return-boundary","readyTestid":"current-user"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"customer","do":"click","testid":"catalog-link","unlessVisible":"item-card"},{"action":"buy","actor":"customer","do":"callAction","input":{"attribute":"data-buy-input","contains":"Keyboard","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"}},{"actor":"customer","do":"expectActionOutcome","outcome":"accepted"},{"actor":"customer","do":"reload","settleMs":1000},{"actor":"customer","do":"ensureSignedIn","name":"return-boundary","readyTestid":"current-user"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"customer","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"action":"ship","actor":"staff","do":"callAction","from":"customer","input":{"attribute":"data-ship-input","contains":"Keyboard","testid":"order-item"},"namedAction":{"args":[0],"id":"ship","params":[{"in":"body","name":"orderId","wireType":"u64"}],"path":"/api/fulfilment/ship","reducer":"ship_order"}},{"actor":"staff","do":"expectActionOutcome","outcome":"accepted"},{"actor":"customer","do":"reload","settleMs":1000},{"actor":"customer","do":"ensureSignedIn","name":"return-boundary","readyTestid":"current-user"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"customer","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"customer","do":"expect","ignoreCase":true,"in":{"contains":"Keyboard","testid":"order-item"},"testid":"order-status","value":"shipped"},{"action":"returnItem","actor":"customer","do":"callAction","input":{"attribute":"data-return-input","contains":"Keyboard","testid":"order-line"},"namedAction":{"args":[0,0],"id":"returnItem","method":"POST","params":[{"in":"path","name":"orderId","placeholder":"{orderId}","wireType":"u64"},{"in":"path","name":"itemId","placeholder":"{itemId}","wireType":"u64"}],"path":"/api/orders/{orderId}/items/{itemId}/return","reducer":"return_order_item"}},{"actor":"customer","do":"expectActionOutcome","outcome":"accepted"},{"actor":"customer","do":"reload","settleMs":1000},{"actor":"customer","do":"ensureSignedIn","name":"return-boundary","readyTestid":"current-user"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"customer","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"customer","do":"expect","ignoreCase":true,"in":{"contains":"Keyboard","testid":"order-item"},"testid":"order-status","value":"returned"},{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"click","testid":"admin-link"},{"actor":"admin","as":"pending-revenue","do":"recordNumber","testid":"admin-revenue"},{"as":"pending-East","do":"dbRecordStock","item":"Desk Lamp","warehouse":"East"},{"as":"pending-West","do":"dbRecordStock","item":"Desk Lamp","warehouse":"West"},{"actor":"customer","do":"expect","ignoreCase":true,"in":{"contains":"Desk Lamp","testid":"order-item"},"testid":"order-status","value":"pending"}]},"packId":"ecommerce.l3.order-returns-features","requiresFeatures":["ecommerce.feature.purchasing","ecommerce.progression.fulfilment-queue"],"role":"feature","source":"scenarios/progression-order-return-boundary.json","stablePackId":"ecommerce.returns-pricing"}],"id":"selected-source-081","scenario":{"level":3,"writeUrlPattern":null},"source":"scenarios/progression-order-return-boundary.json"},{"checkGroups":[{"checkGroupId":"cancellation-and-return","feature":{"actors":["customer","staff","admin"],"criteria":[{"id":"3c","steps":[{"actor":"customer","do":"click","in":{"contains":"Keyboard","testid":"order-item"},"testid":"return-item"},{"actor":"customer","contains":"Keyboard","containsText":"returned","do":"expect","ignoreCase":true,"testid":"order-item","within":10000},{"actor":"customer","do":"freshClient"},{"actor":"customer-fresh","do":"signIn","name":"return-complete"},{"actor":"customer-fresh","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"customer-fresh","do":"click","testid":"orders-toggle"},{"actor":"customer-fresh","contains":"Keyboard","containsText":"returned","do":"expect","ignoreCase":true,"testid":"order-item","within":10000},{"actor":"admin","do":"reload","settleMs":1000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","testid":"admin-link","unlessVisible":"admin-revenue"},{"actor":"admin","do":"expectNumber","plus":0,"relativeTo":"return-revenue-before","testid":"admin-revenue","within":10000},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"customer","do":"click","ifAvailable":true,"testid":"catalog-link","within":1000},{"do":"dbExpectStock","item":"Keyboard","plus":0,"relativeTo":"return-stock-before"}]}],"id":330,"setup":[{"actor":"customer","do":"signUp","name":"return-complete"},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"staff","do":"click","testid":"staff-link"},{"actor":"admin","do":"click","testid":"admin-link"},{"actor":"customer","do":"expectNumber","equals":89,"in":{"contains":"Keyboard","testid":"item-card"},"testid":"item-price"},{"as":"return-stock-before","do":"dbRecordStock","item":"Keyboard"},{"actor":"admin","as":"return-revenue-before","do":"recordNumber","testid":"admin-revenue"},{"actor":"customer","do":"click","in":{"contains":"Keyboard","testid":"item-card"},"testid":"buy-now"},{"actor":"staff","do":"reload","settleMs":1000},{"actor":"staff","do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026","readyTestid":"current-user"},{"actor":"staff","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"staff","do":"click","testid":"staff-link","unlessVisible":"queue-item"},{"actor":"staff","contains":"Keyboard","do":"expect","testid":"queue-item","within":10000},{"do":"dbExpectStock","item":"Keyboard","plus":-1,"relativeTo":"return-stock-before"},{"actor":"admin","do":"reload","settleMs":1000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"admin","do":"click","testid":"admin-link","unlessVisible":"admin-revenue"},{"actor":"admin","do":"expectNumber","plus":89,"relativeTo":"return-revenue-before","testid":"admin-revenue","within":10000},{"actor":"staff","do":"click","in":{"contains":"Keyboard","testid":"queue-item"},"testid":"ship-submit"},{"actor":"customer","do":"reload","settleMs":1000},{"actor":"customer","do":"ensureSignedIn","name":"return-complete","readyTestid":"current-user"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"customer","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"customer","do":"expect","ignoreCase":true,"in":{"contains":"Keyboard","testid":"order-item"},"testid":"order-status","value":"shipped","within":10000}]},"packId":"ecommerce.l3.order-returns-features","requiresFeatures":["ecommerce.feature.purchasing","ecommerce.progression.fulfilment-queue"],"role":"feature","source":"scenarios/progression-order-return-complete.json","stablePackId":"ecommerce.returns-pricing"}],"id":"selected-source-082","scenario":{"level":3,"writeUrlPattern":null},"source":"scenarios/progression-order-return-complete.json"},{"checkGroups":[{"checkGroupId":"order-support-ownership","feature":{"actors":["owner","other"],"criteria":[{"id":"614b","steps":[{"absent":true,"actor":"other","contains":"Desk Lamp","do":"expect","testid":"support-order-option"},{"action":"linkSupportOrder","actor":"owner","authentication":"actor","do":"callAction","input":{"attribute":"data-action-input","testid":"support-link-order"},"namedAction":{"args":[0,0],"id":"linkSupportOrder","method":"POST","params":[{"in":"path","name":"caseId","placeholder":"{caseId}","wireType":"u64"},{"in":"body","name":"orderId","wireType":"u64"}],"path":"/api/support/cases/{caseId}/order","reducer":"link_support_order"},"settleMs":1500},{"actor":"owner","do":"expectActionOutcome","outcome":"accepted"},{"actor":"owner","contains":"Desk Lamp","do":"expectElementCount","equals":1,"testid":"support-order","within":10000},{"action":"linkSupportOrder","actor":"other","authentication":"actor","do":"callAction","from":"owner","input":{"attribute":"data-action-input","overrides":{"caseId":{"actor":"other","attribute":"data-entity-id","contains":"Other order case","testid":"support-ticket"}},"testid":"support-link-order"},"namedAction":{"args":[0,0],"id":"linkSupportOrder","method":"POST","params":[{"in":"path","name":"caseId","placeholder":"{caseId}","wireType":"u64"},{"in":"body","name":"orderId","wireType":"u64"}],"path":"/api/support/cases/{caseId}/order","reducer":"link_support_order"},"settleMs":1500},{"actor":"other","do":"expectActionOutcome","outcome":"refused"},{"actor":"other","do":"freshClient"},{"actor":"other-fresh","do":"signIn","name":"order-boundary-other"},{"actor":"other-fresh","do":"click","testid":"support-link"},{"absent":true,"actor":"other-fresh","contains":"Desk Lamp","do":"expect","in":{"contains":"Other order case","testid":"support-ticket"},"testid":"support-order"},{"actor":"owner","contains":"Desk Lamp","do":"expectElementCount","equals":1,"testid":"support-order","within":10000}]}],"id":614,"setup":[{"actor":"owner","do":"signUp","name":"order-boundary-owner"},{"actor":"owner","do":"click","in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"buy-now"},{"actor":"owner","do":"click","testid":"support-link"},{"actor":"owner","do":"fill","testid":"support-subject","text":"Owner order case"},{"actor":"owner","do":"fill","testid":"support-message","text":"This case belongs to the order owner."},{"actor":"owner","do":"click","testid":"support-submit"},{"actor":"owner","contains":"Desk Lamp","do":"click","in":{"contains":"Owner order case","testid":"support-ticket"},"testid":"support-order-option"},{"actor":"other","do":"signUp","name":"order-boundary-other"},{"actor":"other","do":"click","testid":"support-link"},{"actor":"other","do":"fill","testid":"support-subject","text":"Other order case"},{"actor":"other","do":"fill","testid":"support-message","text":"This is a separate case."},{"actor":"other","do":"click","testid":"support-submit"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","requiresFeatures":["ecommerce.progression.order-support"],"role":"guarantee","source":"scenarios/progression-order-support-boundary.json"}],"id":"selected-source-083","scenario":{"level":4,"writeUrlPattern":null},"source":"scenarios/progression-order-support-boundary.json"},{"checkGroups":[{"checkGroupId":"order-support-owned","feature":{"actors":["owner","staff"],"criteria":[{"id":"614a","steps":[{"actor":"owner","contains":"Desk Lamp","do":"click","in":{"contains":"Owned order case","testid":"support-ticket"},"testid":"support-order-option"},{"actor":"owner","do":"click","in":{"contains":"Owned order case","testid":"support-ticket"},"testid":"support-link-order"},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"staff","do":"click","testid":"staff-link","unlessVisible":"support-assignee"},{"actor":"staff","do":"click","ifAvailable":true,"testid":"support-queue-link","unlessVisible":"support-assignee"},{"actor":"staff","contains":"Desk Lamp","do":"expect","in":{"contains":"Owned order case","testid":"support-ticket"},"testid":"support-order","within":10000}]}],"id":614,"setup":[{"actor":"owner","do":"signUp","name":"order-support-owner"},{"actor":"owner","do":"click","in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"buy-now"},{"actor":"owner","do":"click","testid":"support-link"},{"actor":"owner","do":"fill","testid":"support-subject","text":"Owned order case"},{"actor":"owner","do":"fill","testid":"support-message","text":"Question about my Desk Lamp order."},{"actor":"owner","do":"click","testid":"support-submit"}]},"packId":"ecommerce.progression.order-support","role":"feature","source":"scenarios/progression-order-support-owned.json"}],"id":"selected-source-084","scenario":{"level":4,"writeUrlPattern":null},"source":"scenarios/progression-order-support-owned.json"},{"checkGroups":[{"checkGroupId":"personalized-recommendations","feature":{"actors":["sales-helper","audio-customer","home-customer","computing-customer"],"criteria":[{"id":"403a","steps":[{"actor":"audio-customer","contains":"Headphones","do":"expect","in":{"testid":"recommendations"},"testid":"recommended-item"},{"actor":"home-customer","do":"expectNumber","equals":1,"in":{"contains":"Desk Lamp","testid":"recommended-item"},"testid":"recommendation-rank","within":10000},{"actor":"computing-customer","do":"expectSequence","equals":["Gaming Mouse","Laptop Stand","Webcam"],"in":{"testid":"recommendations"},"testid":"recommended-item","within":10000}]}],"id":403,"setup":[{"actor":"sales-helper","do":"signUp","name":"recommend-sales"},{"actor":"sales-helper","do":"click","in":{"contains":"Desk Lamp","testid":"item-card"},"settleMs":500,"testid":"buy-now"},{"actor":"sales-helper","do":"click","in":{"contains":"Desk Lamp","testid":"item-card"},"settleMs":500,"testid":"buy-now"},{"actor":"sales-helper","do":"click","in":{"contains":"Desk Lamp","testid":"item-card"},"settleMs":500,"testid":"buy-now"},{"actor":"audio-customer","do":"signUp","name":"recommend-audio"},{"actor":"audio-customer","do":"click","in":{"contains":"Bluetooth Speaker","testid":"item-card"},"testid":"buy-now"},{"actor":"home-customer","do":"signUp","name":"recommend-home"},{"actor":"home-customer","do":"click","in":{"contains":"Coffee Grinder","testid":"item-card"},"testid":"buy-now"},{"actor":"computing-customer","do":"signUp","name":"recommend-computing"},{"actor":"computing-customer","do":"click","in":{"contains":"Keyboard","testid":"item-card"},"testid":"buy-now"}]},"packId":"ecommerce.progression.personalized-recommendations","role":"feature","source":"scenarios/progression-personalized-recommendations.json"},{"checkGroupId":"recommendation-profile-isolation","feature":{"actors":["sales-helper","audio-customer","home-customer","computing-customer"],"criteria":[{"id":"403b","steps":[{"actor":"audio-customer","do":"click","in":{"contains":"Headphones","testid":"item-card"},"testid":"buy-now"},{"actor":"audio-customer","contains":"Headphones","do":"waitUntilAbsent","in":{"testid":"recommendations"},"testid":"recommended-item","within":10000},{"actor":"home-customer","do":"expectNumber","equals":1,"in":{"contains":"Desk Lamp","testid":"recommended-item"},"testid":"recommendation-rank","within":10000},{"actor":"computing-customer","do":"expectSequence","equals":["Gaming Mouse","Laptop Stand","Webcam"],"in":{"testid":"recommendations"},"testid":"recommended-item","within":10000}]}],"id":403,"setup":[{"actor":"sales-helper","do":"signUp","name":"recommend-sales"},{"actor":"sales-helper","do":"click","in":{"contains":"Desk Lamp","testid":"item-card"},"settleMs":500,"testid":"buy-now"},{"actor":"sales-helper","do":"click","in":{"contains":"Desk Lamp","testid":"item-card"},"settleMs":500,"testid":"buy-now"},{"actor":"sales-helper","do":"click","in":{"contains":"Desk Lamp","testid":"item-card"},"settleMs":500,"testid":"buy-now"},{"actor":"audio-customer","do":"signUp","name":"recommend-audio"},{"actor":"audio-customer","do":"click","in":{"contains":"Bluetooth Speaker","testid":"item-card"},"testid":"buy-now"},{"actor":"home-customer","do":"signUp","name":"recommend-home"},{"actor":"home-customer","do":"click","in":{"contains":"Coffee Grinder","testid":"item-card"},"testid":"buy-now"},{"actor":"computing-customer","do":"signUp","name":"recommend-computing"},{"actor":"computing-customer","do":"click","in":{"contains":"Keyboard","testid":"item-card"},"testid":"buy-now"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","requiresFeatures":["ecommerce.progression.personalized-recommendations"],"role":"guarantee","source":"scenarios/progression-personalized-recommendations.json"}],"id":"selected-source-085","scenario":{"level":4,"writeUrlPattern":null},"source":"scenarios/progression-personalized-recommendations.json"},{"checkGroups":[{"checkGroupId":"price-history","feature":{"actors":["admin","customer"],"criteria":[{"id":"4c","steps":[{"actor":"customer","do":"fill","enter":true,"settleMs":1500,"testid":"search-input","text":"Desk Lamp"},{"actor":"customer","do":"click","in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"add-to-cart"},{"actor":"customer","do":"click","testid":"cart-toggle"},{"actor":"customer","do":"expectNumber","equals":42,"testid":"cart-total"},{"actor":"admin","do":"fill","in":{"contains":"Desk Lamp","testid":"admin-item-row"},"testid":"price-input","text":"52.00"},{"actor":"admin","do":"click","in":{"contains":"Desk Lamp","testid":"admin-item-row"},"testid":"price-submit"},{"actor":"customer","do":"expectNumber","equals":52,"testid":"cart-total","within":10000},{"action":"checkout","actor":"customer","do":"callAction","namedAction":{"args":[],"id":"checkout","method":"POST","path":"/api/checkout","reducer":"checkout"},"settleMs":1500},{"actor":"customer","do":"expectActionOutcome","outcome":"accepted"},{"actor":"customer","do":"freshClient"},{"actor":"customer-fresh","do":"signIn","name":"price-cart"},{"actor":"customer-fresh","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"customer-fresh","do":"click","testid":"orders-toggle"},{"actor":"customer-fresh","contains":"Desk Lamp","count":1,"do":"expect","testid":"order-item"},{"actor":"customer-fresh","do":"expectNumber","equals":52,"in":{"contains":"Desk Lamp","testid":"order-item"},"testid":"order-total"}]}],"id":420,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"customer","do":"signUp","name":"price-cart"},{"actor":"admin","do":"click","testid":"admin-link"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.progression.price-history-specifications","requiresFeatures":["ecommerce.feature.checkout","ecommerce.l2.price-history-features"],"role":"guarantee","source":"scenarios/progression-price-cart-checkout.json","stablePackId":"ecommerce.returns-pricing"}],"id":"selected-source-086","scenario":{"level":2,"writeUrlPattern":null},"source":"scenarios/progression-price-cart-checkout.json"},{"checkGroups":[{"checkGroupId":"product-bundles","feature":{"actors":["admin","visitor"],"criteria":[{"id":"740a","steps":[{"actor":"admin","do":"fill","testid":"bundle-name-input","text":"Office bundle"},{"actor":"admin","do":"fill","testid":"bundle-price-input","text":"75.00"},{"actor":"admin","do":"fill","testid":"bundle-components-input","text":"[{\"item\":\"Keyboard\",\"quantity\":2},{\"item\":\"Desk Lamp\",\"quantity\":1}]"},{"actor":"admin","do":"click","testid":"bundle-save"},{"actor":"admin","contains":"Office bundle","do":"expect","testid":"bundle-card","within":10000},{"actor":"visitor","do":"reload","settleMs":1000},{"actor":"visitor","do":"click","testid":"bundles-link","unlessVisible":"bundle-card"},{"actor":"visitor","do":"expectNumber","equals":75,"in":{"contains":"Office bundle","testid":"bundle-card"},"testid":"bundle-price","within":10000},{"actor":"visitor","do":"expectElementCount","equals":2,"in":{"contains":"Office bundle","testid":"bundle-card"},"testid":"bundle-component"},{"actor":"visitor","attribute":"data-quantity","contains":"Keyboard","do":"expect","in":{"contains":"Office bundle","testid":"bundle-card"},"testid":"bundle-component","value":"2","within":10000},{"actor":"visitor","attribute":"data-quantity","contains":"Desk Lamp","do":"expect","in":{"contains":"Office bundle","testid":"bundle-card"},"testid":"bundle-component","value":"1","within":10000}]}],"id":740,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"click","testid":"bundles-link","unlessVisible":"bundle-name-input"}]},"packId":"ecommerce.feature.product-bundles","role":"feature","source":"scenarios/progression-product-bundles.json"},{"checkGroupId":"bundle-743","feature":{"actors":["admin","customer"],"criteria":[{"id":"743a","steps":[{"actor":"admin","do":"fill","testid":"bundle-price-input","text":"1.00"},{"action":"saveBundle","actor":"customer","do":"callAction","from":"admin","input":{"attribute":"data-bundle-save-input","testid":"bundle-save"},"namedAction":{"args":["Protected bundle",1,"[{\"item\":\"Keyboard\",\"quantity\":1}]"],"id":"saveBundle","params":[{"in":"body","name":"name"},{"in":"body","name":"price"},{"in":"body","name":"componentsJson"}],"path":"/api/bundles","reducer":"save_bundle"},"settleMs":1000},{"actor":"customer","do":"expectActionOutcome","outcome":"application-refused"},{"actor":"admin","do":"reload","settleMs":1000},{"actor":"admin","do":"click","testid":"bundles-link","unlessVisible":"bundle-card"},{"actor":"admin","do":"expectNumber","equals":75,"in":{"contains":"Protected bundle","testid":"bundle-card"},"testid":"bundle-price","within":10000},{"actor":"admin","attribute":"data-quantity","contains":"Keyboard","do":"expect","in":{"contains":"Protected bundle","testid":"bundle-card"},"testid":"bundle-component","value":"2","within":10000}]}],"id":743,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"click","testid":"bundles-link","unlessVisible":"bundle-name-input"},{"actor":"customer","do":"signUp","name":"bundle-management"},{"actor":"admin","do":"fill","testid":"bundle-name-input","text":"Protected bundle"},{"actor":"admin","do":"fill","testid":"bundle-price-input","text":"75.00"},{"actor":"admin","do":"fill","testid":"bundle-components-input","text":"[{\"item\":\"Keyboard\",\"quantity\":2},{\"item\":\"Desk Lamp\",\"quantity\":1}]"},{"actor":"admin","do":"click","testid":"bundle-save"},{"actor":"admin","contains":"Protected bundle","do":"expect","testid":"bundle-card","within":10000}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.bundle-integrity","requiresFeatures":["ecommerce.feature.product-bundles"],"role":"guarantee","source":"scenarios/progression-product-bundles.json"}],"id":"selected-source-087","scenario":{"level":4,"writeUrlPattern":null},"source":"scenarios/progression-product-bundles.json"},{"checkGroups":[{"checkGroupId":"promotion-checkout-active","feature":{"actors":["staff","activeBuyer","expiredBuyer","firstBuyer","secondBuyer"],"criteria":[{"id":"621a","steps":[{"actor":"activeBuyer","do":"click","in":{"contains":"Keyboard","testid":"item-card"},"testid":"add-to-cart"},{"actor":"activeBuyer","do":"click","testid":"cart-toggle"},{"actor":"activeBuyer","do":"fill","testid":"cart-promotion","text":"LIVE10"},{"actor":"activeBuyer","do":"click","testid":"apply-promotion"},{"actor":"activeBuyer","do":"click","testid":"checkout-submit"},{"actor":"activeBuyer","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"activeBuyer","do":"click","testid":"orders-toggle"},{"actor":"activeBuyer","do":"expectNumber","equals":8.9,"in":{"contains":"Keyboard","testid":"order-item"},"testid":"order-discount"}]}],"id":621,"setup":[{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"staff","do":"click","testid":"staff-link","unlessVisible":"promotions-link"},{"actor":"staff","do":"click","testid":"promotions-link","unlessVisible":"promotion-code"},{"actor":"staff","do":"fill","testid":"promotion-code","text":"LIVE10"},{"actor":"staff","do":"fill","testid":"promotion-discount","text":"10"},{"actor":"staff","do":"fill","testid":"promotion-start","text":"2020-01-01"},{"actor":"staff","do":"fill","testid":"promotion-end","text":"2099-12-31"},{"actor":"staff","do":"fill","testid":"promotion-limit","text":"10"},{"actor":"staff","do":"click","testid":"promotion-submit"},{"actor":"staff","do":"fill","testid":"promotion-code","text":"OLD10"},{"actor":"staff","do":"fill","testid":"promotion-discount","text":"10"},{"actor":"staff","do":"fill","testid":"promotion-start","text":"2000-01-01"},{"actor":"staff","do":"fill","testid":"promotion-end","text":"2000-12-31"},{"actor":"staff","do":"fill","testid":"promotion-limit","text":"10"},{"actor":"staff","do":"click","testid":"promotion-submit"},{"actor":"staff","do":"fill","testid":"promotion-code","text":"ONCE10"},{"actor":"staff","do":"fill","testid":"promotion-discount","text":"10"},{"actor":"staff","do":"fill","testid":"promotion-start","text":"2020-01-01"},{"actor":"staff","do":"fill","testid":"promotion-end","text":"2099-12-31"},{"actor":"staff","do":"fill","testid":"promotion-limit","text":"1"},{"actor":"staff","do":"click","testid":"promotion-submit"},{"actor":"activeBuyer","do":"signUp","name":"promotion-active"},{"actor":"expiredBuyer","do":"signUp","name":"promotion-expired"},{"actor":"firstBuyer","do":"signUp","name":"promotion-first"},{"actor":"secondBuyer","do":"signUp","name":"promotion-second"}]},"packId":"ecommerce.progression.promotion-checkout","role":"feature","source":"scenarios/progression-promotion-checkout.json"},{"checkGroupId":"promotion-checkout-expired","feature":{"actors":["staff","activeBuyer","expiredBuyer","firstBuyer","secondBuyer"],"criteria":[{"id":"621b","steps":[{"actor":"expiredBuyer","do":"click","in":{"contains":"Keyboard","testid":"item-card"},"testid":"add-to-cart"},{"actor":"expiredBuyer","do":"click","testid":"cart-toggle"},{"actor":"expiredBuyer","do":"fill","testid":"cart-promotion","text":"OLD10"},{"actor":"expiredBuyer","do":"click","testid":"apply-promotion"},{"actor":"expiredBuyer","do":"expect","testid":"promotion-error"}]}],"id":621,"setup":[{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"staff","do":"click","testid":"staff-link","unlessVisible":"promotions-link"},{"actor":"staff","do":"click","testid":"promotions-link","unlessVisible":"promotion-code"},{"actor":"staff","do":"fill","testid":"promotion-code","text":"LIVE10"},{"actor":"staff","do":"fill","testid":"promotion-discount","text":"10"},{"actor":"staff","do":"fill","testid":"promotion-start","text":"2020-01-01"},{"actor":"staff","do":"fill","testid":"promotion-end","text":"2099-12-31"},{"actor":"staff","do":"fill","testid":"promotion-limit","text":"10"},{"actor":"staff","do":"click","testid":"promotion-submit"},{"actor":"staff","do":"fill","testid":"promotion-code","text":"OLD10"},{"actor":"staff","do":"fill","testid":"promotion-discount","text":"10"},{"actor":"staff","do":"fill","testid":"promotion-start","text":"2000-01-01"},{"actor":"staff","do":"fill","testid":"promotion-end","text":"2000-12-31"},{"actor":"staff","do":"fill","testid":"promotion-limit","text":"10"},{"actor":"staff","do":"click","testid":"promotion-submit"},{"actor":"staff","do":"fill","testid":"promotion-code","text":"ONCE10"},{"actor":"staff","do":"fill","testid":"promotion-discount","text":"10"},{"actor":"staff","do":"fill","testid":"promotion-start","text":"2020-01-01"},{"actor":"staff","do":"fill","testid":"promotion-end","text":"2099-12-31"},{"actor":"staff","do":"fill","testid":"promotion-limit","text":"1"},{"actor":"staff","do":"click","testid":"promotion-submit"},{"actor":"activeBuyer","do":"signUp","name":"promotion-active"},{"actor":"expiredBuyer","do":"signUp","name":"promotion-expired"},{"actor":"firstBuyer","do":"signUp","name":"promotion-first"},{"actor":"secondBuyer","do":"signUp","name":"promotion-second"}]},"packId":"ecommerce.progression.promotion-checkout","role":"feature","source":"scenarios/progression-promotion-checkout.json"},{"checkGroupId":"promotion-checkout-exhausted","feature":{"actors":["staff","activeBuyer","expiredBuyer","firstBuyer","secondBuyer"],"criteria":[{"id":"621c","steps":[{"actor":"firstBuyer","do":"click","in":{"contains":"Keyboard","testid":"item-card"},"testid":"add-to-cart"},{"actor":"firstBuyer","do":"click","testid":"cart-toggle"},{"actor":"firstBuyer","do":"fill","testid":"cart-promotion","text":"ONCE10"},{"actor":"firstBuyer","do":"click","testid":"apply-promotion"},{"actor":"firstBuyer","do":"click","testid":"checkout-submit"},{"actor":"secondBuyer","do":"click","in":{"contains":"Keyboard","testid":"item-card"},"testid":"add-to-cart"},{"actor":"secondBuyer","do":"click","testid":"cart-toggle"},{"actor":"secondBuyer","do":"fill","testid":"cart-promotion","text":"ONCE10"},{"actor":"secondBuyer","do":"click","testid":"apply-promotion"},{"actor":"secondBuyer","do":"expect","testid":"promotion-error"}]}],"id":621,"setup":[{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"staff","do":"click","testid":"staff-link","unlessVisible":"promotions-link"},{"actor":"staff","do":"click","testid":"promotions-link","unlessVisible":"promotion-code"},{"actor":"staff","do":"fill","testid":"promotion-code","text":"LIVE10"},{"actor":"staff","do":"fill","testid":"promotion-discount","text":"10"},{"actor":"staff","do":"fill","testid":"promotion-start","text":"2020-01-01"},{"actor":"staff","do":"fill","testid":"promotion-end","text":"2099-12-31"},{"actor":"staff","do":"fill","testid":"promotion-limit","text":"10"},{"actor":"staff","do":"click","testid":"promotion-submit"},{"actor":"staff","do":"fill","testid":"promotion-code","text":"OLD10"},{"actor":"staff","do":"fill","testid":"promotion-discount","text":"10"},{"actor":"staff","do":"fill","testid":"promotion-start","text":"2000-01-01"},{"actor":"staff","do":"fill","testid":"promotion-end","text":"2000-12-31"},{"actor":"staff","do":"fill","testid":"promotion-limit","text":"10"},{"actor":"staff","do":"click","testid":"promotion-submit"},{"actor":"staff","do":"fill","testid":"promotion-code","text":"ONCE10"},{"actor":"staff","do":"fill","testid":"promotion-discount","text":"10"},{"actor":"staff","do":"fill","testid":"promotion-start","text":"2020-01-01"},{"actor":"staff","do":"fill","testid":"promotion-end","text":"2099-12-31"},{"actor":"staff","do":"fill","testid":"promotion-limit","text":"1"},{"actor":"staff","do":"click","testid":"promotion-submit"},{"actor":"activeBuyer","do":"signUp","name":"promotion-active"},{"actor":"expiredBuyer","do":"signUp","name":"promotion-expired"},{"actor":"firstBuyer","do":"signUp","name":"promotion-first"},{"actor":"secondBuyer","do":"signUp","name":"promotion-second"}]},"packId":"ecommerce.progression.promotion-checkout","role":"feature","source":"scenarios/progression-promotion-checkout.json"}],"id":"selected-source-088","scenario":{"level":5,"writeUrlPattern":null},"source":"scenarios/progression-promotion-checkout.json"},{"checkGroups":[{"checkGroupId":"promotion-report-redemptions","feature":{"actors":["staff","buyer"],"criteria":[{"id":"622a","steps":[{"actor":"staff","do":"expectNumber","equals":1,"in":{"contains":"REPORT10","testid":"promotion-report"},"testid":"promotion-redemptions"}]}],"id":622,"setup":[{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"staff","do":"click","testid":"staff-link","unlessVisible":"promotions-link"},{"actor":"staff","do":"click","testid":"promotions-link","unlessVisible":"promotion-code"},{"actor":"staff","do":"fill","testid":"promotion-code","text":"REPORT10"},{"actor":"staff","do":"fill","testid":"promotion-discount","text":"10"},{"actor":"staff","do":"fill","testid":"promotion-start","text":"2020-01-01"},{"actor":"staff","do":"fill","testid":"promotion-end","text":"2099-12-31"},{"actor":"staff","do":"fill","testid":"promotion-limit","text":"2"},{"actor":"staff","do":"click","testid":"promotion-submit"},{"actor":"buyer","do":"signUp","name":"promotion-report-buyer"},{"actor":"buyer","do":"click","in":{"contains":"Keyboard","testid":"item-card"},"testid":"add-to-cart"},{"actor":"buyer","do":"click","testid":"cart-toggle"},{"actor":"buyer","do":"fill","testid":"cart-promotion","text":"REPORT10"},{"actor":"buyer","do":"click","testid":"apply-promotion"},{"actor":"buyer","do":"click","testid":"checkout-submit"}]},"packId":"ecommerce.progression.promotion-reporting","role":"feature","source":"scenarios/progression-promotion-reporting.json"},{"checkGroupId":"promotion-report-revenue","feature":{"actors":["staff","buyer"],"criteria":[{"id":"622b","steps":[{"actor":"staff","do":"expectNumber","equals":80.1,"in":{"contains":"REPORT10","testid":"promotion-report"},"testid":"promotion-revenue"}]}],"id":622,"setup":[{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"staff","do":"click","testid":"staff-link","unlessVisible":"promotions-link"},{"actor":"staff","do":"click","testid":"promotions-link","unlessVisible":"promotion-code"},{"actor":"staff","do":"fill","testid":"promotion-code","text":"REPORT10"},{"actor":"staff","do":"fill","testid":"promotion-discount","text":"10"},{"actor":"staff","do":"fill","testid":"promotion-start","text":"2020-01-01"},{"actor":"staff","do":"fill","testid":"promotion-end","text":"2099-12-31"},{"actor":"staff","do":"fill","testid":"promotion-limit","text":"2"},{"actor":"staff","do":"click","testid":"promotion-submit"},{"actor":"buyer","do":"signUp","name":"promotion-report-buyer"},{"actor":"buyer","do":"click","in":{"contains":"Keyboard","testid":"item-card"},"testid":"add-to-cart"},{"actor":"buyer","do":"click","testid":"cart-toggle"},{"actor":"buyer","do":"fill","testid":"cart-promotion","text":"REPORT10"},{"actor":"buyer","do":"click","testid":"apply-promotion"},{"actor":"buyer","do":"click","testid":"checkout-submit"}]},"packId":"ecommerce.progression.promotion-reporting","role":"feature","source":"scenarios/progression-promotion-reporting.json"}],"id":"selected-source-089","scenario":{"level":5,"writeUrlPattern":null},"source":"scenarios/progression-promotion-reporting.json"},{"checkGroups":[{"checkGroupId":"promotion-rule-values","feature":{"actors":["staff","customer"],"criteria":[{"id":"620a","steps":[{"actor":"staff","do":"click","testid":"promotions-link","unlessVisible":"promotion-code"},{"actor":"staff","do":"fill","testid":"promotion-code","text":"SAVE10"},{"actor":"staff","do":"fill","testid":"promotion-discount","text":"10"},{"actor":"staff","do":"fill","testid":"promotion-start","text":"2099-01-01"},{"actor":"staff","do":"fill","testid":"promotion-end","text":"2099-12-31"},{"actor":"staff","do":"fill","testid":"promotion-limit","text":"2"},{"actor":"staff","do":"click","testid":"promotion-submit"},{"actor":"staff","do":"expectNumber","equals":10,"in":{"contains":"SAVE10","testid":"promotion-item"},"testid":"promotion-discount"},{"actor":"staff","contains":"2099-01-01","do":"expect","in":{"contains":"SAVE10","testid":"promotion-item"},"testid":"promotion-start"},{"actor":"staff","contains":"2099-12-31","do":"expect","in":{"contains":"SAVE10","testid":"promotion-item"},"testid":"promotion-end"},{"actor":"staff","do":"expectNumber","equals":2,"in":{"contains":"SAVE10","testid":"promotion-item"},"testid":"promotion-limit"}]}],"id":620,"setup":[{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"customer","do":"signUp","name":"promotion-customer"},{"actor":"staff","do":"click","testid":"staff-link"}]},"packId":"ecommerce.progression.promotion-rules","role":"feature","source":"scenarios/progression-promotion-rules.json"},{"checkGroupId":"promotion-management-boundary","feature":{"actors":["staff","customer"],"criteria":[{"id":"620b","steps":[{"actor":"staff","do":"click","testid":"promotions-link","unlessVisible":"promotion-code"},{"actor":"staff","do":"fill","testid":"promotion-code","text":"ACCESS10"},{"actor":"staff","do":"fill","testid":"promotion-discount","text":"10"},{"actor":"staff","do":"fill","testid":"promotion-start","text":"2099-01-01"},{"actor":"staff","do":"fill","testid":"promotion-end","text":"2099-12-31"},{"actor":"staff","do":"fill","testid":"promotion-limit","text":"2"},{"actor":"staff","do":"click","testid":"promotion-submit"},{"actor":"staff","do":"reload","settleMs":1000},{"actor":"staff","do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026","readyTestid":"current-user"},{"actor":"staff","do":"click","ifAvailable":true,"testid":"staff-link","unlessVisible":"promotion-code"},{"actor":"staff","do":"click","testid":"promotions-link","unlessVisible":"promotion-code"},{"actor":"staff","contains":"ACCESS10","do":"expect","testid":"promotion-item","within":10000},{"absent":true,"actor":"customer","do":"expect","testid":"promotions-link"},{"actor":"customer","do":"replayAs","from":"staff","match":"ACCESS10","namedAction":{"args":["ACCESS10",10,4070908800000000,4102444740000000,2],"id":"createPromotion","params":[{"in":"body","name":"code"},{"in":"body","name":"discountPercent"},{"in":"body","name":"startMicros"},{"in":"body","name":"endMicros"},{"in":"body","name":"usageLimit"}],"path":"/api/promotions","reducer":"create_promotion"},"settleMs":1500,"swap":{"find":"ACCESS10","with":"HACK10"}},{"actor":"customer","do":"expectReplayRejected"},{"absent":true,"actor":"staff","contains":"HACK10","do":"expect","testid":"promotion-item"}]}],"id":620,"setup":[{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"customer","do":"signUp","name":"promotion-customer"},{"actor":"staff","do":"click","testid":"staff-link"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","requiresFeatures":["ecommerce.progression.promotion-rules"],"role":"guarantee","source":"scenarios/progression-promotion-rules.json"}],"id":"selected-source-090","scenario":{"level":5,"writeUrlPattern":null},"source":"scenarios/progression-promotion-rules.json"},{"checkGroups":[{"checkGroupId":"purchase-order","feature":{"actors":["buyer"],"criteria":[{"id":"3c","steps":[{"actor":"buyer","do":"click","in":{"contains":"Coffee Grinder","testid":"item-card"},"testid":"buy-now"},{"actor":"buyer","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"buyer","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"buyer","contains":"Coffee Grinder","do":"expect","testid":"order-item"},{"actor":"buyer","do":"expectNumber","equals":64,"in":{"contains":"Coffee Grinder","testid":"order-item"},"testid":"order-total"}]}],"id":3,"setup":[{"actor":"buyer","do":"signUp","name":"purchase-buyer"}]},"packId":"ecommerce.feature.purchasing","role":"feature","source":"scenarios/progression-purchasing.json"}],"id":"selected-source-091","scenario":{"level":1,"writeUrlPattern":null},"source":"scenarios/progression-purchasing.json"},{"checkGroups":[{"checkGroupId":"recommendation-feedback","feature":{"actors":["customer","other"],"criteria":[{"id":"504a","steps":[{"absent":true,"actor":"customer","contains":"Headphones","do":"expect","testid":"recommended-item","within":10000}]}],"id":504,"setup":[{"actor":"customer","do":"signUp","name":"feedback-owner"},{"actor":"customer","do":"click","in":{"contains":"Bluetooth Speaker","testid":"item-card"},"testid":"buy-now"},{"actor":"other","do":"signUp","name":"feedback-other"},{"actor":"other","do":"click","in":{"contains":"Bluetooth Speaker","testid":"item-card"},"testid":"buy-now"},{"actor":"customer","contains":"Headphones","do":"expect","testid":"recommended-item"},{"actor":"other","contains":"Headphones","do":"expect","testid":"recommended-item"},{"actor":"customer","do":"click","in":{"contains":"Headphones","testid":"recommended-item"},"testid":"dismiss-recommendation"}]},"packId":"ecommerce.progression.recommendation-feedback","role":"feature","source":"scenarios/progression-recommendation-feedback.json"},{"checkGroupId":"recommendation-feedback-privacy","feature":{"actors":["customer","other"],"criteria":[{"id":"504b","steps":[{"actor":"customer","contains":"Headphones","do":"waitUntilAbsent","testid":"recommended-item","within":10000},{"actor":"other","contains":"Headphones","do":"expect","testid":"recommended-item"}]}],"id":504,"setup":[{"actor":"customer","do":"signUp","name":"feedback-owner"},{"actor":"customer","do":"click","in":{"contains":"Bluetooth Speaker","testid":"item-card"},"testid":"buy-now"},{"actor":"other","do":"signUp","name":"feedback-other"},{"actor":"other","do":"click","in":{"contains":"Bluetooth Speaker","testid":"item-card"},"testid":"buy-now"},{"actor":"customer","contains":"Headphones","do":"expect","testid":"recommended-item"},{"actor":"other","contains":"Headphones","do":"expect","testid":"recommended-item"},{"actor":"customer","do":"click","in":{"contains":"Headphones","testid":"recommended-item"},"testid":"dismiss-recommendation"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","requiresFeatures":["ecommerce.progression.recommendation-feedback"],"role":"guarantee","source":"scenarios/progression-recommendation-feedback.json"},{"checkGroupId":"recommendation-feedback-restart","feature":{"actors":["customer","other"],"criteria":[{"id":"504c","steps":[{"actor":"customer","do":"reload","settleMs":3000},{"actor":"customer","do":"ensureSignedIn","name":"feedback-owner","readyTestid":"current-user"},{"absent":true,"actor":"customer","contains":"Headphones","do":"expect","testid":"recommended-item"},{"do":"restartBackend","settleMs":1000},{"actor":"customer","do":"freshClient"},{"actor":"customer-fresh","do":"signIn","name":"feedback-owner"},{"actor":"customer-fresh","do":"expect","testid":"recommendations","within":10000},{"absent":true,"actor":"customer-fresh","contains":"Headphones","do":"expect","testid":"recommended-item"}]}],"id":504,"setup":[{"actor":"customer","do":"signUp","name":"feedback-owner"},{"actor":"customer","do":"click","in":{"contains":"Bluetooth Speaker","testid":"item-card"},"testid":"buy-now"},{"actor":"other","do":"signUp","name":"feedback-other"},{"actor":"other","do":"click","in":{"contains":"Bluetooth Speaker","testid":"item-card"},"testid":"buy-now"},{"actor":"customer","contains":"Headphones","do":"expect","testid":"recommended-item"},{"actor":"other","contains":"Headphones","do":"expect","testid":"recommended-item"},{"actor":"customer","do":"click","in":{"contains":"Headphones","testid":"recommended-item"},"testid":"dismiss-recommendation"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.state-durability","requiresFeatures":["ecommerce.progression.recommendation-feedback"],"role":"guarantee","source":"scenarios/progression-recommendation-feedback.json"}],"id":"selected-source-092","scenario":{"level":5,"writeUrlPattern":null},"source":"scenarios/progression-recommendation-feedback.json"},{"checkGroups":[{"checkGroupId":"review-eligibility-direct","feature":{"actors":["owner","stranger"],"criteria":[{"id":"618a","steps":[{"action":"submitReview","actor":"owner","do":"callAction","from":"owner","input":{"attribute":"data-buy-input","contains":"Keyboard","testid":"item-card"},"namedAction":{"args":[0,5,"eligible progression review"],"id":"submitReview","method":"POST","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"},{"in":"body","name":"rating"},{"in":"body","name":"comment"}],"path":"/api/items/:id/reviews","reducer":"submit_review"},"settleMs":1500},{"actor":"owner","do":"expectActionOutcome","outcome":"accepted"},{"actor":"owner","do":"openItem","item":"Keyboard"},{"actor":"owner","contains":"eligible progression review","do":"expect","testid":"review-item","within":10000},{"action":"submitReview","actor":"stranger","do":"callAction","from":"stranger","input":{"attribute":"data-buy-input","contains":"Keyboard","testid":"item-card"},"namedAction":{"args":[0,5,"never bought this"],"id":"submitReview","method":"POST","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"},{"in":"body","name":"rating"},{"in":"body","name":"comment"}],"path":"/api/items/:id/reviews","reducer":"submit_review"},"settleMs":1500},{"actor":"stranger","do":"expectActionOutcome","outcome":"application-refused","routeProvenBy":"owner"},{"actor":"stranger","do":"freshClient"},{"actor":"stranger-fresh","do":"signIn","name":"review-stranger"},{"actor":"stranger-fresh","do":"openItem","item":"Keyboard"},{"actor":"stranger-fresh","contains":"eligible progression review","do":"expect","testid":"review-item","within":10000},{"absent":true,"actor":"stranger-fresh","contains":"never bought this","do":"expect","testid":"review-item","within":3000}]}],"id":618,"setup":[{"actor":"owner","do":"signUp","name":"review-owner"},{"actor":"stranger","do":"signUp","name":"review-stranger"},{"action":"buy","actor":"owner","do":"callAction","input":{"attribute":"data-buy-input","contains":"Keyboard","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"}},{"actor":"owner","do":"expectActionOutcome","outcome":"accepted"},{"actor":"owner","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"owner","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"owner","contains":"Keyboard","do":"expect","testid":"order-item","within":10000},{"actor":"owner","do":"click","ifAvailable":true,"testid":"overlay-close"},{"actor":"owner","do":"click","ifAvailable":true,"testid":"catalog-link"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.progression.review-access-specifications","requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.reviews"],"role":"guarantee","source":"scenarios/progression-review-access.json"}],"id":"selected-source-093","scenario":{"level":3,"writeUrlPattern":null},"source":"scenarios/progression-review-access.json"},{"checkGroups":[{"checkGroupId":"stored-review-script","feature":{"actors":["owner","writer","reader"],"criteria":[{"id":"9180a","steps":[{"action":"submitReview","actor":"owner","do":"callAction","input":{"attribute":"data-buy-input","contains":"Keyboard","testid":"item-card"},"namedAction":{"args":[0,5,"Benign stored review"],"id":"submitReview","method":"POST","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"},{"in":"body","name":"rating"},{"in":"body","name":"comment"}],"path":"/api/items/:id/reviews","reducer":"submit_review"},"settleMs":0},{"actor":"owner","do":"expectActionOutcome","outcome":"accepted"},{"action":"submitReview","actor":"writer","do":"callAction","input":{"attribute":"data-buy-input","contains":"Keyboard","testid":"item-card"},"namedAction":{"args":[0,5,"Stored review marker "],"id":"submitReview","method":"POST","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"},{"in":"body","name":"rating"},{"in":"body","name":"comment"}],"path":"/api/items/:id/reviews","reducer":"submit_review"},"settleMs":0},{"actor":"writer","do":"expectActionOutcome","outcome":"completed","routeProvenBy":"owner"},{"actor":"owner","do":"openItem","item":"Keyboard"},{"actor":"owner","contains":"Benign stored review","do":"expect","testid":"review-item","within":10000},{"actor":"owner","do":"wait","ms":1000},{"actor":"owner","do":"expectNoScriptExecution"},{"actor":"reader","do":"freshClient"},{"actor":"reader-fresh","do":"signIn","name":"script-review-reader"},{"actor":"reader-fresh","do":"armScriptCanary"},{"actor":"reader-fresh","do":"openItem","item":"Keyboard"},{"actor":"reader-fresh","contains":"Benign stored review","do":"expect","testid":"review-item","within":10000},{"actor":"reader-fresh","do":"wait","ms":1000},{"actor":"reader-fresh","do":"expectNoScriptExecution"}]}],"id":9180,"setup":[{"actor":"owner","do":"signUp","name":"script-review-owner"},{"actor":"reader","do":"signUp","name":"script-review-reader"},{"actor":"writer","do":"signUp","name":"script-review-writer"},{"action":"buy","actor":"owner","do":"callAction","input":{"attribute":"data-buy-input","contains":"Keyboard","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"}},{"actor":"owner","do":"expectActionOutcome","outcome":"accepted"},{"action":"buy","actor":"writer","do":"callAction","input":{"attribute":"data-buy-input","contains":"Keyboard","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"}},{"actor":"writer","do":"expectActionOutcome","outcome":"accepted"},{"actor":"owner","do":"armScriptCanary"}]},"observations":["unmentioned"],"packId":"ecommerce.progression.review-access-specifications","requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.reviews"],"role":"guarantee","source":"scenarios/progression-review-script.json"}],"id":"selected-source-094","scenario":{"level":3,"writeUrlPattern":null},"source":"scenarios/progression-review-script.json"},{"checkGroups":[{"checkGroupId":"search-ordering","feature":{"actors":["visitor","buyer"],"criteria":[{"id":"402b","steps":[{"actor":"visitor","do":"expectSequence","equals":["Air Purifier","Bluetooth Speaker","Coffee Grinder","Desk Lamp","Espresso Machine","Gaming Mouse","Headphones","Induction Cooktop","Keyboard","Laptop Stand"],"in":{"testid":"search-results"},"testid":"item-name"},{"actor":"visitor","do":"fill","enter":true,"testid":"search-input","text":"e"},{"actor":"visitor","do":"fill","testid":"minimum-price","text":""},{"actor":"visitor","do":"click","ifAvailable":true,"testid":"filter-apply"},{"actor":"visitor","do":"expectSequence","equals":["Air Purifier","Bluetooth Speaker","Coffee Grinder","Desk Lamp","Espresso Machine","Gaming Mouse","Headphones","Keyboard","Mirrorless Camera","USB Cable"],"in":{"testid":"search-results"},"testid":"item-name"},{"actor":"visitor","do":"fill","enter":true,"testid":"search-input","text":""},{"actor":"visitor","do":"expectSequence","equals":["Headphones","Air Purifier","Bluetooth Speaker","Coffee Grinder","Desk Lamp","Espresso Machine","Gaming Mouse","Induction Cooktop","Keyboard","Laptop Stand"],"in":{"testid":"item-list"},"testid":"item-name"}]}],"id":402,"setup":[{"actor":"buyer","do":"signUp","name":"search-order-buyer"},{"as":"before-search-purchase","do":"dbRecordStock","item":"Headphones"},{"actor":"buyer","do":"click","in":{"contains":"Headphones","testid":"item-card"},"testid":"buy-now"},{"do":"dbExpectStock","item":"Headphones","plus":-1,"relativeTo":"before-search-purchase"},{"actor":"visitor","do":"reload","settleMs":0},{"actor":"visitor","do":"fill","testid":"minimum-price","text":"1"},{"actor":"visitor","do":"click","ifAvailable":true,"testid":"filter-apply"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.search-ordering","requiresFeatures":["ecommerce.feature.purchasing","ecommerce.progression.faceted-search"],"role":"guarantee","source":"scenarios/progression-search-ordering.json"}],"id":"selected-source-095","scenario":{"level":3,"writeUrlPattern":null},"source":"scenarios/progression-search-ordering.json"},{"checkGroups":[{"checkGroupId":"shipping-accounting","feature":{"actors":["customer","admin","staff"],"criteria":[{"id":"202e","steps":[{"as":"stock-before-purchase","do":"dbRecordStock","item":"Keyboard"},{"actor":"admin","as":"revenue-before-purchase","do":"recordNumber","testid":"admin-revenue"},{"actor":"customer","do":"click","in":{"contains":"Keyboard","testid":"item-card"},"testid":"buy-now"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"customer","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"customer","do":"expect","ignoreCase":true,"in":{"contains":"Keyboard","testid":"order-item"},"testid":"order-status","value":"pending","within":10000},{"do":"dbExpectStock","item":"Keyboard","plus":-1,"relativeTo":"stock-before-purchase"},{"actor":"admin","do":"reload","settleMs":2000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"admin-link"},{"actor":"admin","do":"expectNumber","plus":89,"relativeTo":"revenue-before-purchase","testid":"admin-revenue","within":10000},{"actor":"admin","as":"revenue-before-ship","do":"recordNumber","testid":"admin-revenue"},{"as":"East-before-ship","do":"dbRecordStock","item":"Keyboard","warehouse":"East"},{"as":"West-before-ship","do":"dbRecordStock","item":"Keyboard","warehouse":"West"},{"actor":"staff","do":"reload","settleMs":2000},{"actor":"staff","do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026","readyTestid":"current-user"},{"actor":"staff","do":"click","ifAvailable":true,"testid":"staff-link"},{"action":"ship","actor":"staff","do":"callAction","from":"customer","input":{"attribute":"data-ship-input","contains":"Keyboard","testid":"order-item"},"namedAction":{"args":[0],"id":"ship","params":[{"in":"body","name":"orderId","wireType":"u64"}],"path":"/api/fulfilment/ship","reducer":"ship_order"},"settleMs":0},{"actor":"staff","do":"expectActionOutcome","outcome":"accepted"},{"actor":"customer","do":"reload","settleMs":2000},{"actor":"customer","do":"ensureSignedIn","name":"shipping-accounting","readyTestid":"current-user"},{"actor":"customer","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"customer","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"customer","do":"expect","ignoreCase":true,"in":{"contains":"Keyboard","testid":"order-item"},"testid":"order-status","value":"shipped","within":10000},{"do":"dbExpectStock","item":"Keyboard","plus":0,"relativeTo":"East-before-ship","warehouse":"East"},{"do":"dbExpectStock","item":"Keyboard","plus":0,"relativeTo":"West-before-ship","warehouse":"West"},{"actor":"admin","do":"reload","settleMs":2000},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"admin-link"},{"actor":"admin","do":"expectNumber","plus":0,"relativeTo":"revenue-before-ship","testid":"admin-revenue","within":10000}]}],"id":202,"setup":[{"actor":"customer","do":"signUp","name":"shipping-accounting"},{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"click","testid":"admin-link"},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"staff","do":"click","testid":"staff-link"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.progression.inventory-conservation-specifications","requiresFeatures":["ecommerce.feature.purchasing","ecommerce.feature.warehouse-admin","ecommerce.progression.fulfilment-queue"],"role":"guarantee","source":"scenarios/progression-shipping-accounting.json","stablePackId":"ecommerce.inventory-operations"}],"id":"selected-source-096","scenario":{"level":3,"writeUrlPattern":null},"source":"scenarios/progression-shipping-accounting.json"},{"checkGroups":[{"checkGroupId":"signed-out-purchase","feature":{"actors":["visitor"],"criteria":[{"id":"3a","steps":[{"actor":"visitor","as":"keyboard-before-guest","do":"recordNumber","in":{"contains":"Keyboard","testid":"item-card"},"testid":"item-stock"},{"actor":"visitor","do":"click","ifAvailable":true,"in":{"contains":"Keyboard","testid":"item-card"},"settleMs":1500,"testid":"buy-now"},{"actor":"visitor","do":"reload","settleMs":2000},{"actor":"visitor","do":"click","ifAvailable":true,"testid":"overlay-close"},{"actor":"visitor","do":"click","ifAvailable":true,"testid":"catalog-link"},{"actor":"visitor","do":"expectNumber","in":{"contains":"Keyboard","testid":"item-card"},"plus":0,"relativeTo":"keyboard-before-guest","testid":"item-stock"}]}],"id":3,"setup":[{"actor":"visitor","contains":"Keyboard","do":"expect","testid":"item-card"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","requiresFeatures":["ecommerce.feature.purchasing"],"role":"guarantee","source":"scenarios/progression-signed-out-purchase.json"}],"id":"selected-source-097","scenario":{"level":1,"writeUrlPattern":null},"source":"scenarios/progression-signed-out-purchase.json"},{"checkGroups":[{"checkGroupId":"split-tender-refunds-751","feature":{"actors":["owner","staff"],"criteria":[{"id":"751a","steps":[{"actor":"staff","do":"click","in":{"contains":"Split refund 751","testid":"support-ticket"},"testid":"support-refund"},{"actor":"owner","do":"freshClient"},{"actor":"owner-fresh","do":"signIn","name":"credit-owner-751"},{"actor":"owner-fresh","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"owner-fresh","do":"click","testid":"orders-toggle"},{"actor":"owner-fresh","contains":"Desk Lamp","do":"expectElementCount","equals":1,"testid":"refund-entry","within":10000},{"actor":"owner-fresh","do":"expectNumber","equals":42,"in":{"contains":"Desk Lamp","testid":"order-item"},"testid":"order-refund-total"},{"actor":"owner-fresh","do":"expectNumber","equals":10,"in":{"contains":"Desk Lamp","testid":"refund-entry"},"testid":"refund-credit-amount"},{"actor":"owner-fresh","do":"expectNumber","equals":32,"in":{"contains":"Desk Lamp","testid":"refund-entry"},"testid":"refund-external-amount"},{"actor":"owner-fresh","do":"click","testid":"credit-link"},{"actor":"owner-fresh","attribute":"aria-busy","do":"expect","testid":"credit-panel","value":"false","within":10000},{"actor":"owner-fresh","do":"expectNumber","equals":10,"testid":"credit-balance"}]}],"id":751,"setup":[{"actor":"owner","do":"signUp","name":"credit-owner-751"},{"actor":"owner","do":"click","testid":"credit-link","unlessVisible":"credit-panel"},{"actor":"owner","attribute":"aria-busy","do":"expect","testid":"credit-panel","value":"false","within":10000},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"staff","do":"click","testid":"credit-link","unlessVisible":"credit-panel"},{"actor":"staff","attribute":"aria-busy","do":"expect","testid":"credit-panel","value":"false","within":10000},{"actor":"staff","do":"fill","testid":"credit-amount-input","text":"10.00"},{"actor":"staff","do":"fill","testid":"credit-reference-input","text":"credit-751"},{"action":"grantCredit","actor":"staff","do":"callAction","from":"staff","input":{"attribute":"data-action-input","overrides":{"accountId":{"actor":"owner","attribute":"data-account-id","testid":"credit-panel"}},"testid":"credit-grant"},"namedAction":{"args":[0,1000,""],"id":"grantCredit","method":"POST","params":[{"in":"body","name":"accountId","wireType":"u64"},{"in":"body","name":"amountMinor"},{"in":"body","name":"reference"}],"path":"/api/staff/credit","reducer":"grant_credit"},"settleMs":0},{"actor":"staff","do":"expectActionOutcome","outcome":"accepted"},{"actor":"owner","do":"reload","settleMs":1000},{"actor":"owner","do":"ensureSignedIn","name":"credit-owner-751","readyTestid":"current-user"},{"actor":"owner","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"owner","do":"click","testid":"credit-link","unlessVisible":"credit-balance"},{"actor":"owner","do":"expectNumber","equals":10,"testid":"credit-balance","within":10000},{"actor":"owner","do":"click","testid":"catalog-link"},{"actor":"owner","do":"click","in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"add-to-cart"},{"actor":"owner","do":"click","testid":"cart-toggle"},{"actor":"owner","do":"expectNumber","equals":42,"testid":"cart-total"},{"actor":"owner","do":"click","testid":"credit-checkout"},{"actor":"owner","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"owner","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"owner","do":"expectNumber","equals":10,"in":{"contains":"Desk Lamp","testid":"order-item"},"testid":"payment-credit-amount","within":10000},{"actor":"owner","do":"expectNumber","equals":32,"in":{"contains":"Desk Lamp","testid":"order-item"},"testid":"payment-external-amount"},{"actor":"owner","do":"click","testid":"support-link"},{"actor":"owner","do":"fill","testid":"support-subject","text":"Split refund 751"},{"actor":"owner","do":"fill","testid":"support-message","text":"Please refund this order."},{"actor":"owner","do":"click","testid":"support-submit"},{"actor":"owner","contains":"Desk Lamp","do":"click","in":{"contains":"Split refund 751","testid":"support-ticket"},"testid":"support-order-option"},{"actor":"owner","do":"click","in":{"contains":"Split refund 751","testid":"support-ticket"},"testid":"support-link-order"},{"actor":"staff","do":"click","testid":"staff-link","unlessVisible":"support-assignee"},{"actor":"staff","do":"click","ifAvailable":true,"testid":"support-queue-link","unlessVisible":"support-assignee","within":1000}]},"packId":"ecommerce.feature.split-tender-refunds","requiresFeatures":["ecommerce.feature.split-tender-refunds","ecommerce.feature.store-credit","ecommerce.progression.support-refunds"],"role":"feature","source":"scenarios/progression-split-tender-refunds.json"},{"checkGroupId":"production-756","feature":{"actors":["owner","staff","staff2"],"criteria":[{"id":"756a","steps":[{"action":"supportRefund","actors":["staff","staff2"],"do":"callConcurrently","from":"staff","input":{"attribute":"data-refund-input","contains":"Split refund 756","testid":"support-ticket"},"namedAction":{"args":[0],"id":"supportRefund","method":"POST","params":[{"in":"path","name":"caseId","placeholder":"{caseId}","wireType":"u64"}],"path":"/api/support/cases/{caseId}/refund","reducer":"support_refund"},"settleMs":0},{"do":"expectCallOutcomes"},{"actor":"owner","do":"freshClient"},{"actor":"owner-fresh","do":"signIn","name":"credit-owner-756"},{"actor":"owner-fresh","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"owner-fresh","do":"click","testid":"orders-toggle"},{"actor":"owner-fresh","contains":"Desk Lamp","do":"expectElementCount","equals":1,"testid":"refund-entry","within":10000},{"actor":"owner-fresh","do":"expectNumber","equals":42,"in":{"contains":"Desk Lamp","testid":"order-item"},"testid":"order-refund-total"},{"actor":"owner-fresh","do":"expectNumber","equals":10,"in":{"contains":"Desk Lamp","testid":"refund-entry"},"testid":"refund-credit-amount"},{"actor":"owner-fresh","do":"expectNumber","equals":32,"in":{"contains":"Desk Lamp","testid":"refund-entry"},"testid":"refund-external-amount"},{"actor":"owner-fresh","do":"click","testid":"credit-link"},{"actor":"owner-fresh","attribute":"aria-busy","do":"expect","testid":"credit-panel","value":"false","within":10000},{"actor":"owner-fresh","do":"expectNumber","equals":10,"testid":"credit-balance"},{"do":"restartBackend","settleMs":1000},{"actor":"owner","do":"freshClient"},{"actor":"owner-fresh","do":"signIn","name":"credit-owner-756"},{"actor":"owner-fresh","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"owner-fresh","do":"click","testid":"orders-toggle"},{"actor":"owner-fresh","contains":"Desk Lamp","do":"expectElementCount","equals":1,"testid":"refund-entry","within":10000},{"actor":"owner-fresh","do":"expectNumber","equals":42,"in":{"contains":"Desk Lamp","testid":"order-item"},"testid":"order-refund-total"},{"actor":"owner-fresh","do":"expectNumber","equals":10,"in":{"contains":"Desk Lamp","testid":"refund-entry"},"testid":"refund-credit-amount"},{"actor":"owner-fresh","do":"expectNumber","equals":32,"in":{"contains":"Desk Lamp","testid":"refund-entry"},"testid":"refund-external-amount"},{"actor":"owner-fresh","do":"click","testid":"credit-link"},{"actor":"owner-fresh","attribute":"aria-busy","do":"expect","testid":"credit-panel","value":"false","within":10000},{"actor":"owner-fresh","do":"expectNumber","equals":10,"testid":"credit-balance"}]}],"id":756,"setup":[{"actor":"owner","do":"signUp","name":"credit-owner-756"},{"actor":"owner","do":"click","testid":"credit-link","unlessVisible":"credit-panel"},{"actor":"owner","attribute":"aria-busy","do":"expect","testid":"credit-panel","value":"false","within":10000},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"staff","do":"click","testid":"credit-link","unlessVisible":"credit-panel"},{"actor":"staff","attribute":"aria-busy","do":"expect","testid":"credit-panel","value":"false","within":10000},{"actor":"staff","do":"fill","testid":"credit-amount-input","text":"10.00"},{"actor":"staff","do":"fill","testid":"credit-reference-input","text":"credit-756"},{"action":"grantCredit","actor":"staff","do":"callAction","from":"staff","input":{"attribute":"data-action-input","overrides":{"accountId":{"actor":"owner","attribute":"data-account-id","testid":"credit-panel"}},"testid":"credit-grant"},"namedAction":{"args":[0,1000,""],"id":"grantCredit","method":"POST","params":[{"in":"body","name":"accountId","wireType":"u64"},{"in":"body","name":"amountMinor"},{"in":"body","name":"reference"}],"path":"/api/staff/credit","reducer":"grant_credit"},"settleMs":0},{"actor":"staff","do":"expectActionOutcome","outcome":"accepted"},{"actor":"owner","do":"reload","settleMs":1000},{"actor":"owner","do":"ensureSignedIn","name":"credit-owner-756","readyTestid":"current-user"},{"actor":"owner","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"owner","do":"click","testid":"credit-link","unlessVisible":"credit-balance"},{"actor":"owner","do":"expectNumber","equals":10,"testid":"credit-balance","within":10000},{"actor":"owner","do":"click","testid":"catalog-link"},{"actor":"owner","do":"click","in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"add-to-cart"},{"actor":"owner","do":"click","testid":"cart-toggle"},{"actor":"owner","do":"expectNumber","equals":42,"testid":"cart-total"},{"actor":"owner","do":"click","testid":"credit-checkout"},{"actor":"owner","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"owner","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"owner","do":"expectNumber","equals":10,"in":{"contains":"Desk Lamp","testid":"order-item"},"testid":"payment-credit-amount","within":10000},{"actor":"owner","do":"expectNumber","equals":32,"in":{"contains":"Desk Lamp","testid":"order-item"},"testid":"payment-external-amount"},{"actor":"owner","do":"click","testid":"support-link"},{"actor":"owner","do":"fill","testid":"support-subject","text":"Split refund 756"},{"actor":"owner","do":"fill","testid":"support-message","text":"Please refund this order."},{"actor":"owner","do":"click","testid":"support-submit"},{"actor":"owner","contains":"Desk Lamp","do":"click","in":{"contains":"Split refund 756","testid":"support-ticket"},"testid":"support-order-option"},{"actor":"owner","do":"click","in":{"contains":"Split refund 756","testid":"support-ticket"},"testid":"support-link-order"},{"actor":"staff","do":"click","testid":"staff-link","unlessVisible":"support-assignee"},{"actor":"staff","do":"click","ifAvailable":true,"testid":"support-queue-link","unlessVisible":"support-assignee","within":1000},{"actor":"staff2","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.split-tender-refunds","requiresFeatures":["ecommerce.feature.split-tender-refunds","ecommerce.feature.store-credit","ecommerce.progression.support-refunds"],"role":"guarantee","source":"scenarios/progression-split-tender-refunds.json"}],"id":"selected-source-098","scenario":{"level":6,"writeUrlPattern":null},"source":"scenarios/progression-split-tender-refunds.json"},{"checkGroups":[{"checkGroupId":"staff-access","feature":{"actors":["customer","staff","admin","authorized"],"criteria":[{"id":"601a","steps":[{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"staff","do":"click","testid":"staff-link"},{"actor":"staff","do":"expect","testid":"staff-area","within":6000},{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"click","testid":"staff-link"},{"actor":"admin","do":"expect","testid":"staff-area","within":6000}]}],"id":601,"setup":[]},"packId":"ecommerce.progression.staff-access","role":"feature","source":"scenarios/progression-staff-access.json"},{"checkGroupId":"staff-area-boundary","feature":{"actors":["customer","staff","admin","authorized"],"criteria":[{"id":"601b","steps":[{"actor":"authorized","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"authorized","do":"click","testid":"staff-link"},{"actor":"authorized","do":"expect","testid":"staff-area"},{"actor":"customer","do":"signIn","exact":true,"name":"customer","password":"stackbench-customer-2026"},{"actor":"customer","do":"click","ifAvailable":true,"settleMs":1500,"testid":"staff-link"},{"absent":true,"actor":"customer","do":"expect","testid":"staff-area"}]}],"id":601,"setup":[]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","requiresFeatures":["ecommerce.progression.staff-access"],"role":"guarantee","source":"scenarios/progression-staff-access.json"}],"id":"selected-source-099","scenario":{"level":1,"writeUrlPattern":null},"source":"scenarios/progression-staff-access.json"},{"checkGroups":[{"checkGroupId":"staff-activity","feature":{"actors":["admin","staff","customer"],"criteria":[{"id":"624a","steps":[{"actor":"staff","do":"click","testid":"staff-link"},{"actor":"staff","do":"click","testid":"activity-link"},{"actor":"staff","contains":"Activity Mug","do":"expect","testid":"activity-entry","within":10000},{"actor":"staff","contains":"admin","do":"expect","in":{"contains":"Activity Mug","testid":"activity-entry"},"testid":"activity-actor"},{"actor":"staff","contains":"creat","do":"expect","in":{"contains":"Activity Mug","testid":"activity-entry"},"testid":"activity-action"},{"actor":"staff","contains":"Activity Mug","do":"expect","in":{"contains":"Activity Mug","testid":"activity-entry"},"testid":"activity-subject"},{"actor":"staff","do":"expect","in":{"contains":"Activity Mug","testid":"activity-entry"},"testid":"activity-time"}]}],"id":624,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"customer","do":"signIn","exact":true,"name":"customer","password":"stackbench-customer-2026"},{"actor":"admin","do":"click","testid":"admin-link"},{"actor":"admin","do":"fill","testid":"catalog-name","text":"Activity Mug"},{"actor":"admin","do":"fill","testid":"catalog-category","text":"Kitchen"},{"actor":"admin","do":"fill","testid":"catalog-price","text":"43.00"},{"actor":"admin","do":"fill","testid":"catalog-variants","text":"Green"},{"actor":"admin","do":"click","testid":"catalog-save"}]},"packId":"ecommerce.progression.staff-activity","role":"feature","source":"scenarios/progression-staff-activity.json"},{"checkGroupId":"staff-activity-privacy","feature":{"actors":["admin","staff","customer"],"criteria":[{"id":"624b","steps":[{"absent":true,"actor":"customer","do":"expect","testid":"activity-link"}]}],"id":624,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"customer","do":"signIn","exact":true,"name":"customer","password":"stackbench-customer-2026"},{"actor":"admin","do":"click","testid":"admin-link"},{"actor":"admin","do":"fill","testid":"catalog-name","text":"Activity Mug"},{"actor":"admin","do":"fill","testid":"catalog-category","text":"Kitchen"},{"actor":"admin","do":"fill","testid":"catalog-price","text":"43.00"},{"actor":"admin","do":"fill","testid":"catalog-variants","text":"Green"},{"actor":"admin","do":"click","testid":"catalog-save"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","requiresFeatures":["ecommerce.progression.staff-activity"],"role":"guarantee","source":"scenarios/progression-staff-activity.json"}],"id":"selected-source-100","scenario":{"level":5,"writeUrlPattern":null},"source":"scenarios/progression-staff-activity.json"},{"checkGroups":[{"checkGroupId":"staff-roles","feature":{"actors":["admin","replayAdmin","staff","roleAdmin","promotedStaff"],"criteria":[{"id":"621c","steps":[{"actor":"admin","do":"expect","in":{"testid":"staff-role-account-staff"},"testid":"staff-role-select","value":"inventory","within":10000}]}],"id":621,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"expect","testid":"admin-link","within":6000},{"actor":"admin","do":"click","testid":"admin-link","unlessVisible":"staff-role-account-staff"},{"actor":"admin","do":"fill","in":{"testid":"staff-role-account-staff"},"testid":"staff-role-select","text":"inventory"},{"actor":"admin","do":"click","in":{"testid":"staff-role-account-staff"},"testid":"staff-role-save"}]},"packId":"ecommerce.progression.staff-roles","role":"feature","source":"scenarios/progression-staff-roles.json"},{"checkGroupId":"staff-role-reload","feature":{"actors":["admin","replayAdmin","staff","roleAdmin","promotedStaff"],"criteria":[{"id":"621a","steps":[{"actor":"admin","do":"reload","settleMs":2500},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","ifAvailable":true,"testid":"admin-link","unlessVisible":"staff-role-account-staff"},{"actor":"admin","do":"expect","in":{"testid":"staff-role-account-staff"},"testid":"staff-role-select","value":"inventory","within":10000},{"do":"restartBackend","settleMs":1000},{"actor":"admin","do":"freshClient"},{"actor":"admin-fresh","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin-fresh","do":"click","testid":"admin-link","unlessVisible":"staff-role-account-staff"},{"actor":"admin-fresh","do":"expect","in":{"testid":"staff-role-account-staff"},"testid":"staff-role-select","value":"inventory","within":10000}]}],"id":621,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"expect","testid":"admin-link","within":6000},{"actor":"admin","do":"click","testid":"admin-link","unlessVisible":"staff-role-account-staff"},{"actor":"admin","do":"fill","in":{"testid":"staff-role-account-staff"},"testid":"staff-role-select","text":"inventory"},{"actor":"admin","do":"click","in":{"testid":"staff-role-account-staff"},"testid":"staff-role-save"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.state-durability","requiresFeatures":["ecommerce.progression.staff-roles"],"role":"guarantee","source":"scenarios/progression-staff-roles.json"},{"checkGroupId":"staff-role-boundary","feature":{"actors":["admin","replayAdmin","staff","roleAdmin","promotedStaff"],"criteria":[{"id":"621b","steps":[{"actor":"replayAdmin","do":"reload","settleMs":0},{"actor":"replayAdmin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"replayAdmin","do":"expect","testid":"admin-link","within":6000},{"actor":"replayAdmin","do":"click","testid":"admin-link","unlessVisible":"staff-role-account-staff"},{"actor":"replayAdmin","do":"fill","in":{"testid":"staff-role-account-staff"},"testid":"staff-role-select","text":"staff"},{"actor":"replayAdmin","do":"click","in":{"testid":"staff-role-account-staff"},"testid":"staff-role-save"},{"actor":"replayAdmin","do":"reload","settleMs":1000},{"actor":"replayAdmin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"replayAdmin","do":"click","ifAvailable":true,"testid":"admin-link","unlessVisible":"staff-role-account-staff"},{"actor":"replayAdmin","do":"expect","in":{"testid":"staff-role-account-staff"},"testid":"staff-role-select","value":"staff","within":10000},{"actor":"staff","do":"reload","settleMs":0},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"staff","do":"click","ifAvailable":true,"testid":"staff-link"},{"absent":true,"actor":"staff","do":"expect","testid":"staff-role-save"},{"actor":"staff","do":"replayAs","from":"replayAdmin","match":"role","namedAction":{"args":[0,"inventory"],"id":"assignStaffRole","method":"PUT","params":[{"in":"path","name":"accountId","placeholder":":id","wireType":"u64"},{"in":"body","name":"role"}],"path":"/api/staff/:id/role","reducer":"assign_staff_role"},"namedTarget":{"attribute":"data-account-id","testid":"staff-role-account-staff","valueType":"string"},"settleMs":1500,"swap":{"find":"\"role\":\"staff\"","with":"\"role\":\"inventory\""}},{"actor":"staff","do":"expectReplayRejected"},{"actor":"replayAdmin","do":"reload","settleMs":1000},{"actor":"replayAdmin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"replayAdmin","do":"click","ifAvailable":true,"testid":"admin-link","unlessVisible":"staff-role-account-staff"},{"actor":"replayAdmin","do":"expect","in":{"testid":"staff-role-account-staff"},"testid":"staff-role-select","value":"staff","within":10000}]}],"id":621,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"expect","testid":"admin-link","within":6000},{"actor":"admin","do":"click","testid":"admin-link","unlessVisible":"staff-role-account-staff"},{"actor":"admin","do":"fill","in":{"testid":"staff-role-account-staff"},"testid":"staff-role-select","text":"inventory"},{"actor":"admin","do":"click","in":{"testid":"staff-role-account-staff"},"testid":"staff-role-save"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","requiresFeatures":["ecommerce.progression.staff-roles"],"role":"guarantee","source":"scenarios/progression-staff-roles.json"},{"checkGroupId":"staff-role-revocation","feature":{"actors":["admin","replayAdmin","staff","roleAdmin","promotedStaff"],"criteria":[{"id":"621d","steps":[{"actor":"roleAdmin","do":"reload","settleMs":0},{"actor":"roleAdmin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"roleAdmin","do":"click","testid":"admin-link","unlessVisible":"staff-role-account-staff"},{"actor":"roleAdmin","do":"replayAs","from":"roleAdmin","match":"__role-revocation-named-action__","namedAction":{"args":[0,"admin"],"id":"assignStaffRole","method":"PUT","params":[{"in":"path","name":"accountId","placeholder":":id","wireType":"u64"},{"in":"body","name":"role"}],"path":"/api/staff/:id/role","reducer":"assign_staff_role"},"namedTarget":{"attribute":"data-account-id","testid":"staff-role-account-staff","valueType":"string"},"settleMs":0},{"actor":"roleAdmin","do":"expectReplayCompleted","requireAccepted":true},{"actor":"roleAdmin","do":"reload","settleMs":0},{"actor":"roleAdmin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"roleAdmin","do":"click","ifAvailable":true,"testid":"admin-link","unlessVisible":"staff-role-account-staff"},{"actor":"roleAdmin","do":"expect","in":{"testid":"staff-role-account-staff"},"testid":"staff-role-select","value":"admin","within":10000},{"actor":"promotedStaff","do":"reload","settleMs":0},{"actor":"promotedStaff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"promotedStaff","do":"replayAs","from":"roleAdmin","match":"__role-revocation-named-action__","namedAction":{"args":[0,"admin"],"id":"assignStaffRole","method":"PUT","params":[{"in":"path","name":"accountId","placeholder":":id","wireType":"u64"},{"in":"body","name":"role"}],"path":"/api/staff/:id/role","reducer":"assign_staff_role"},"namedTarget":{"attribute":"data-account-id","testid":"staff-role-account-staff","valueType":"string"},"settleMs":0},{"actor":"promotedStaff","do":"expectReplayCompleted","requireAccepted":true},{"actor":"roleAdmin","do":"replayAs","from":"roleAdmin","match":"__role-revocation-named-action__","namedAction":{"args":[0,"staff"],"id":"assignStaffRole","method":"PUT","params":[{"in":"path","name":"accountId","placeholder":":id","wireType":"u64"},{"in":"body","name":"role"}],"path":"/api/staff/:id/role","reducer":"assign_staff_role"},"namedTarget":{"attribute":"data-account-id","testid":"staff-role-account-staff","valueType":"string"},"settleMs":0},{"actor":"roleAdmin","do":"expectReplayCompleted","requireAccepted":true},{"actor":"roleAdmin","do":"reload","settleMs":0},{"actor":"roleAdmin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"roleAdmin","do":"click","ifAvailable":true,"testid":"admin-link","unlessVisible":"staff-role-account-staff"},{"actor":"roleAdmin","do":"expect","in":{"testid":"staff-role-account-staff"},"testid":"staff-role-select","value":"staff","within":10000},{"actor":"promotedStaff","do":"replayAs","from":"roleAdmin","match":"__role-revocation-named-action__","namedAction":{"args":[0,"admin"],"id":"assignStaffRole","method":"PUT","params":[{"in":"path","name":"accountId","placeholder":":id","wireType":"u64"},{"in":"body","name":"role"}],"path":"/api/staff/:id/role","reducer":"assign_staff_role"},"namedTarget":{"attribute":"data-account-id","testid":"staff-role-account-staff","valueType":"string"},"settleMs":0},{"actor":"promotedStaff","do":"expectReplayRejected"},{"actor":"roleAdmin","do":"reload","settleMs":0},{"actor":"roleAdmin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"roleAdmin","do":"click","ifAvailable":true,"testid":"admin-link","unlessVisible":"staff-role-account-staff"},{"actor":"roleAdmin","do":"expect","in":{"testid":"staff-role-account-staff"},"testid":"staff-role-select","value":"staff","within":10000}]}],"id":621,"setup":[{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"admin","do":"expect","testid":"admin-link","within":6000},{"actor":"admin","do":"click","testid":"admin-link","unlessVisible":"staff-role-account-staff"},{"actor":"admin","do":"fill","in":{"testid":"staff-role-account-staff"},"testid":"staff-role-select","text":"inventory"},{"actor":"admin","do":"click","in":{"testid":"staff-role-account-staff"},"testid":"staff-role-save"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","requiresFeatures":["ecommerce.progression.staff-roles"],"role":"guarantee","source":"scenarios/progression-staff-roles.json"}],"id":"selected-source-101","scenario":{"level":2,"writeUrlPattern":null},"source":"scenarios/progression-staff-roles.json"},{"checkGroups":[{"checkGroupId":"stock-alert-delivery","feature":{"actors":["subscriber","admin"],"criteria":[{"id":"631c","steps":[{"actor":"subscriber","do":"freshClient"},{"actor":"subscriber-fresh","do":"signIn","name":"stock-subscriber"},{"actor":"subscriber-fresh","do":"click","testid":"notifications-toggle","unlessVisible":"notifications-panel"},{"actor":"subscriber-fresh","attribute":"aria-busy","do":"expect","testid":"notifications-panel","value":"false","within":10000},{"actor":"subscriber-fresh","contains":"Air Purifier","do":"expectElementCount","equals":0,"testid":"stock-alert-delivery"},{"actor":"admin","do":"click","testid":"admin-link"},{"action":"restock","actor":"admin","do":"callAction","input":{"attribute":"data-restock-input","contains":"Air Purifier","testid":"admin-location-row"},"namedAction":{"args":[0,0,1],"id":"restock","params":[{"in":"body","name":"itemId","wireType":"u64"},{"in":"body","name":"warehouseId","wireType":"u64"},{"in":"body","name":"quantity"}],"path":"/api/admin/restock","reducer":"admin_restock"},"settleMs":0},{"actor":"admin","do":"expectActionOutcome","outcome":"accepted"},{"actor":"admin","do":"wait","ms":10000},{"actor":"subscriber","do":"freshClient"},{"actor":"subscriber-fresh","do":"signIn","name":"stock-subscriber"},{"actor":"subscriber-fresh","do":"click","testid":"notifications-toggle","unlessVisible":"notifications-panel"},{"actor":"subscriber-fresh","attribute":"aria-busy","do":"expect","testid":"notifications-panel","value":"false","within":10000},{"actor":"subscriber-fresh","contains":"Air Purifier","do":"expect","testid":"stock-alert-delivery","within":10000}]}],"id":631,"setup":[{"actor":"subscriber","do":"signUp","name":"stock-subscriber"},{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"dbSetStock","item":"Air Purifier","quantity":0,"settleMs":1000,"warehouse":"East"},{"do":"dbSetStock","item":"Air Purifier","quantity":0,"settleMs":1000,"warehouse":"West"},{"actor":"subscriber","do":"reload","settleMs":1000},{"actor":"subscriber","do":"ensureSignedIn","name":"stock-subscriber","readyTestid":"current-user"},{"actor":"subscriber","do":"click","in":{"contains":"Air Purifier","testid":"item-card"},"testid":"stock-alert"},{"actor":"subscriber","attribute":"data-submit-state","contains":"Air Purifier","do":"expect","testid":"item-card","value":"succeeded","within":10000}]},"packId":"ecommerce.progression.stock-alerts","requiresFeatures":["ecommerce.feature.warehouse-admin"],"role":"feature","source":"scenarios/progression-stock-alert-delivery.json"}],"id":"selected-source-102","scenario":{"level":5,"writeUrlPattern":null},"source":"scenarios/progression-stock-alert-delivery.json"},{"checkGroups":[{"checkGroupId":"stock-alert-deduplication","feature":{"actors":["subscriber","other","admin"],"criteria":[{"id":"631a","steps":[{"actor":"subscriber","do":"freshClient"},{"actor":"subscriber-fresh","do":"signIn","name":"stock-subscriber"},{"actor":"subscriber-fresh","do":"click","testid":"notifications-toggle","unlessVisible":"notifications-panel"},{"actor":"subscriber-fresh","attribute":"aria-busy","do":"expect","testid":"notifications-panel","value":"false","within":10000},{"actor":"subscriber-fresh","contains":"Air Purifier","do":"expectElementCount","equals":1,"testid":"stock-alert-delivery","within":10000},{"action":"restock","actor":"admin","do":"callAction","input":{"attribute":"data-restock-input","contains":"Air Purifier","testid":"admin-location-row"},"namedAction":{"args":[0,0,1],"id":"restock","params":[{"in":"body","name":"itemId","wireType":"u64"},{"in":"body","name":"warehouseId","wireType":"u64"},{"in":"body","name":"quantity"}],"path":"/api/admin/restock","reducer":"admin_restock"},"settleMs":0},{"actor":"admin","do":"expectActionOutcome","outcome":"accepted"},{"actor":"admin","do":"wait","ms":10000},{"actor":"subscriber","do":"freshClient"},{"actor":"subscriber-fresh","do":"signIn","name":"stock-subscriber"},{"actor":"subscriber-fresh","do":"click","testid":"notifications-toggle","unlessVisible":"notifications-panel"},{"actor":"subscriber-fresh","attribute":"aria-busy","do":"expect","testid":"notifications-panel","value":"false","within":10000},{"actor":"subscriber-fresh","contains":"Air Purifier","do":"expectElementCount","equals":1,"testid":"stock-alert-delivery","within":10000}]}],"id":631,"setup":[{"actor":"subscriber","do":"signUp","name":"stock-subscriber"},{"actor":"other","do":"signUp","name":"stock-other"},{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"dbSetStock","item":"Air Purifier","quantity":0,"settleMs":1000,"warehouse":"East"},{"do":"dbSetStock","item":"Air Purifier","quantity":0,"settleMs":1000,"warehouse":"West"},{"actor":"subscriber","do":"reload","settleMs":1000},{"actor":"subscriber","do":"ensureSignedIn","name":"stock-subscriber","readyTestid":"current-user"},{"actor":"subscriber","do":"click","in":{"contains":"Air Purifier","testid":"item-card"},"testid":"stock-alert"},{"actor":"subscriber","attribute":"data-submit-state","contains":"Air Purifier","do":"expect","testid":"item-card","value":"succeeded","within":10000},{"actor":"admin","do":"click","testid":"admin-link"},{"action":"restock","actor":"admin","do":"callAction","input":{"attribute":"data-restock-input","contains":"Air Purifier","testid":"admin-location-row"},"namedAction":{"args":[0,0,1],"id":"restock","params":[{"in":"body","name":"itemId","wireType":"u64"},{"in":"body","name":"warehouseId","wireType":"u64"},{"in":"body","name":"quantity"}],"path":"/api/admin/restock","reducer":"admin_restock"},"settleMs":0},{"actor":"admin","do":"expectActionOutcome","outcome":"accepted"},{"actor":"admin","do":"wait","ms":10000}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.transactional-integrity","requiresFeatures":["ecommerce.feature.warehouse-admin","ecommerce.progression.stock-alerts"],"role":"guarantee","source":"scenarios/progression-stock-alerts.json"},{"checkGroupId":"stock-alert-privacy","feature":{"actors":["subscriber","other","admin"],"criteria":[{"id":"631b","steps":[{"actor":"subscriber","do":"freshClient"},{"actor":"subscriber-fresh","do":"signIn","name":"stock-subscriber"},{"actor":"subscriber-fresh","do":"click","testid":"notifications-toggle","unlessVisible":"notifications-panel"},{"actor":"subscriber-fresh","attribute":"aria-busy","do":"expect","testid":"notifications-panel","value":"false","within":10000},{"actor":"subscriber-fresh","contains":"Air Purifier","do":"expect","testid":"stock-alert-delivery","within":10000},{"actor":"other","do":"freshClient"},{"actor":"other-fresh","do":"signIn","name":"stock-other"},{"actor":"other-fresh","do":"click","testid":"notifications-toggle","unlessVisible":"notifications-panel"},{"actor":"other-fresh","attribute":"aria-busy","do":"expect","testid":"notifications-panel","value":"false","within":10000},{"absent":true,"actor":"other-fresh","contains":"Air Purifier","do":"expect","testid":"notification-item"}]}],"id":631,"setup":[{"actor":"subscriber","do":"signUp","name":"stock-subscriber"},{"actor":"other","do":"signUp","name":"stock-other"},{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"do":"dbSetStock","item":"Air Purifier","quantity":0,"settleMs":1000,"warehouse":"East"},{"do":"dbSetStock","item":"Air Purifier","quantity":0,"settleMs":1000,"warehouse":"West"},{"actor":"subscriber","do":"reload","settleMs":1000},{"actor":"subscriber","do":"ensureSignedIn","name":"stock-subscriber","readyTestid":"current-user"},{"actor":"subscriber","do":"click","in":{"contains":"Air Purifier","testid":"item-card"},"testid":"stock-alert"},{"actor":"subscriber","attribute":"data-submit-state","contains":"Air Purifier","do":"expect","testid":"item-card","value":"succeeded","within":10000},{"actor":"admin","do":"click","testid":"admin-link"},{"action":"restock","actor":"admin","do":"callAction","input":{"attribute":"data-restock-input","contains":"Air Purifier","testid":"admin-location-row"},"namedAction":{"args":[0,0,1],"id":"restock","params":[{"in":"body","name":"itemId","wireType":"u64"},{"in":"body","name":"warehouseId","wireType":"u64"},{"in":"body","name":"quantity"}],"path":"/api/admin/restock","reducer":"admin_restock"},"settleMs":0},{"actor":"admin","do":"expectActionOutcome","outcome":"accepted"},{"actor":"admin","do":"wait","ms":10000}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","requiresFeatures":["ecommerce.feature.warehouse-admin","ecommerce.progression.stock-alerts"],"role":"guarantee","source":"scenarios/progression-stock-alerts.json"}],"id":"selected-source-103","scenario":{"level":5,"writeUrlPattern":null},"source":"scenarios/progression-stock-alerts.json"},{"checkGroups":[{"checkGroupId":"stock-limit","feature":{"actors":["buyer","watcher","visitor"],"criteria":[{"id":"3d","steps":[{"actor":"buyer","do":"click","in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"buy-now"},{"actor":"buyer","do":"wait","ms":800},{"actor":"buyer","do":"click","in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"buy-now"},{"actor":"buyer","do":"wait","ms":800},{"actor":"buyer","do":"click","in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"buy-now"},{"actor":"buyer","do":"expectNumber","equals":0,"in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"item-stock"},{"actor":"buyer","do":"expect","in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"out-of-stock"},{"action":"buy","actor":"buyer","do":"callAction","input":{"attribute":"data-buy-input","contains":"Desk Lamp","testid":"item-card"},"namedAction":{"args":[0],"id":"buy","params":[{"in":"path","name":"itemId","placeholder":":id","wireType":"u64"}],"path":"/api/items/:id/buy","reducer":"buy_now"},"settleMs":2000},{"actor":"buyer","do":"expectActionOutcome","outcome":"validation-refused"},{"actor":"buyer","do":"reload","settleMs":3000},{"actor":"buyer","do":"ensureSignedIn","name":"eli","readyTestid":"current-user"},{"actor":"buyer","do":"expectNumber","equals":0,"in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"item-stock"}]}],"id":3,"setup":[{"do":"dbSetStock","item":"Desk Lamp","quantity":2,"settleMs":2000,"warehouse":"East"},{"do":"dbSetStock","item":"Desk Lamp","quantity":1,"settleMs":2000,"warehouse":"West"},{"actor":"buyer","do":"signUp","name":"eli"},{"actor":"watcher","do":"signUp","name":"fay"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.concurrency-safety","requiresFeatures":["ecommerce.feature.purchasing"],"role":"guarantee","source":"scenarios/progression-stock-limit.json"}],"id":"selected-source-104","scenario":{"level":1,"writeUrlPattern":null},"source":"scenarios/progression-stock-limit.json"},{"checkGroups":[{"checkGroupId":"store-credit-750","feature":{"actors":["owner","staff","tab"],"criteria":[{"id":"750a","steps":[{"actor":"owner","do":"click","testid":"credit-checkout"},{"actor":"owner","do":"freshClient"},{"actor":"owner-fresh","do":"signIn","name":"credit-owner-750"},{"actor":"owner-fresh","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"owner-fresh","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"owner-fresh","contains":"Desk Lamp","do":"expectElementCount","equals":1,"testid":"order-item","within":10000},{"actor":"owner-fresh","do":"expectNumber","equals":10,"in":{"contains":"Desk Lamp","testid":"order-item"},"testid":"payment-credit-amount"},{"actor":"owner-fresh","do":"expectNumber","equals":32,"in":{"contains":"Desk Lamp","testid":"order-item"},"testid":"payment-external-amount"},{"actor":"owner-fresh","do":"expectNumber","equals":42,"in":{"contains":"Desk Lamp","testid":"order-item"},"testid":"payment-amount"},{"actor":"owner-fresh","do":"click","testid":"credit-link","unlessVisible":"credit-panel"},{"actor":"owner-fresh","attribute":"aria-busy","do":"expect","testid":"credit-panel","value":"false","within":10000},{"actor":"owner-fresh","do":"expectNumber","equals":0,"testid":"credit-balance"}]}],"id":750,"setup":[{"actor":"owner","do":"signUp","name":"credit-owner-750"},{"actor":"owner","do":"click","testid":"credit-link","unlessVisible":"credit-panel"},{"actor":"owner","attribute":"aria-busy","do":"expect","testid":"credit-panel","value":"false","within":10000},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"staff","do":"click","testid":"credit-link","unlessVisible":"credit-panel"},{"actor":"staff","attribute":"aria-busy","do":"expect","testid":"credit-panel","value":"false","within":10000},{"actor":"staff","do":"fill","testid":"credit-amount-input","text":"10.00"},{"actor":"staff","do":"fill","testid":"credit-reference-input","text":"credit-750"},{"action":"grantCredit","actor":"staff","do":"callAction","from":"staff","input":{"attribute":"data-action-input","overrides":{"accountId":{"actor":"owner","attribute":"data-account-id","testid":"credit-panel"}},"testid":"credit-grant"},"namedAction":{"args":[0,1000,""],"id":"grantCredit","method":"POST","params":[{"in":"body","name":"accountId","wireType":"u64"},{"in":"body","name":"amountMinor"},{"in":"body","name":"reference"}],"path":"/api/staff/credit","reducer":"grant_credit"},"settleMs":0},{"actor":"staff","do":"expectActionOutcome","outcome":"accepted"},{"actor":"owner","do":"reload","settleMs":1000},{"actor":"owner","do":"ensureSignedIn","name":"credit-owner-750","readyTestid":"current-user"},{"actor":"owner","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"owner","do":"click","testid":"credit-link","unlessVisible":"credit-balance"},{"actor":"owner","do":"expectNumber","equals":10,"testid":"credit-balance","within":10000},{"actor":"owner","do":"click","testid":"catalog-link"},{"actor":"owner","do":"click","in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"add-to-cart"},{"actor":"owner","do":"click","testid":"cart-toggle"},{"actor":"owner","do":"expectNumber","equals":42,"testid":"cart-total"}]},"packId":"ecommerce.feature.store-credit","role":"feature","source":"scenarios/progression-store-credit.json"},{"checkGroupId":"production-752","feature":{"actors":["owner","staff","tab"],"criteria":[{"id":"752a","steps":[{"action":"grantCredit","actor":"staff","do":"callAction","from":"staff","input":{"attribute":"data-action-input","overrides":{"accountId":{"actor":"owner","attribute":"data-account-id","testid":"credit-panel"}},"testid":"credit-grant"},"namedAction":{"args":[0,1000,""],"id":"grantCredit","method":"POST","params":[{"in":"body","name":"accountId","wireType":"u64"},{"in":"body","name":"amountMinor"},{"in":"body","name":"reference"}],"path":"/api/staff/credit","reducer":"grant_credit"},"settleMs":0},{"actor":"staff","do":"expectActionOutcome","outcome":"completed"},{"actor":"owner","do":"freshClient"},{"actor":"owner-fresh","do":"signIn","name":"credit-owner-752"},{"actor":"owner-fresh","do":"click","testid":"credit-link","unlessVisible":"credit-panel"},{"actor":"owner-fresh","attribute":"aria-busy","do":"expect","testid":"credit-panel","value":"false","within":10000},{"actor":"owner-fresh","do":"expectNumber","equals":10,"testid":"credit-balance"}]}],"id":752,"setup":[{"actor":"owner","do":"signUp","name":"credit-owner-752"},{"actor":"owner","do":"click","testid":"credit-link","unlessVisible":"credit-panel"},{"actor":"owner","attribute":"aria-busy","do":"expect","testid":"credit-panel","value":"false","within":10000},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"staff","do":"click","testid":"credit-link","unlessVisible":"credit-panel"},{"actor":"staff","attribute":"aria-busy","do":"expect","testid":"credit-panel","value":"false","within":10000},{"actor":"staff","do":"fill","testid":"credit-amount-input","text":"10.00"},{"actor":"staff","do":"fill","testid":"credit-reference-input","text":"credit-752"},{"action":"grantCredit","actor":"staff","do":"callAction","from":"staff","input":{"attribute":"data-action-input","overrides":{"accountId":{"actor":"owner","attribute":"data-account-id","testid":"credit-panel"}},"testid":"credit-grant"},"namedAction":{"args":[0,1000,""],"id":"grantCredit","method":"POST","params":[{"in":"body","name":"accountId","wireType":"u64"},{"in":"body","name":"amountMinor"},{"in":"body","name":"reference"}],"path":"/api/staff/credit","reducer":"grant_credit"},"settleMs":0},{"actor":"staff","do":"expectActionOutcome","outcome":"accepted"},{"actor":"owner","do":"reload","settleMs":1000},{"actor":"owner","do":"ensureSignedIn","name":"credit-owner-752","readyTestid":"current-user"},{"actor":"owner","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"owner","do":"click","testid":"credit-link","unlessVisible":"credit-balance"},{"actor":"owner","do":"expectNumber","equals":10,"testid":"credit-balance","within":10000}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.store-credit","requiresFeatures":["ecommerce.feature.store-credit"],"role":"guarantee","source":"scenarios/progression-store-credit.json"},{"checkGroupId":"production-753","feature":{"actors":["owner","staff","tab"],"criteria":[{"id":"753a","steps":[{"actor":"staff","do":"fill","testid":"credit-reference-input","text":"unauthorized-credit-753"},{"action":"grantCredit","actor":"owner","do":"callAction","from":"staff","input":{"attribute":"data-action-input","overrides":{"accountId":{"actor":"owner","attribute":"data-account-id","testid":"credit-panel"}},"testid":"credit-grant"},"namedAction":{"args":[0,1000,""],"id":"grantCredit","method":"POST","params":[{"in":"body","name":"accountId","wireType":"u64"},{"in":"body","name":"amountMinor"},{"in":"body","name":"reference"}],"path":"/api/staff/credit","reducer":"grant_credit"},"settleMs":0},{"actor":"owner","do":"expectActionOutcome","outcome":"refused"},{"actor":"owner","do":"freshClient"},{"actor":"owner-fresh","do":"signIn","name":"credit-owner-753"},{"actor":"owner-fresh","do":"click","testid":"credit-link","unlessVisible":"credit-panel"},{"actor":"owner-fresh","attribute":"aria-busy","do":"expect","testid":"credit-panel","value":"false","within":10000},{"actor":"owner-fresh","do":"expectNumber","equals":10,"testid":"credit-balance"}]}],"id":753,"setup":[{"actor":"owner","do":"signUp","name":"credit-owner-753"},{"actor":"owner","do":"click","testid":"credit-link","unlessVisible":"credit-panel"},{"actor":"owner","attribute":"aria-busy","do":"expect","testid":"credit-panel","value":"false","within":10000},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"staff","do":"click","testid":"credit-link","unlessVisible":"credit-panel"},{"actor":"staff","attribute":"aria-busy","do":"expect","testid":"credit-panel","value":"false","within":10000},{"actor":"staff","do":"fill","testid":"credit-amount-input","text":"10.00"},{"actor":"staff","do":"fill","testid":"credit-reference-input","text":"credit-753"},{"action":"grantCredit","actor":"staff","do":"callAction","from":"staff","input":{"attribute":"data-action-input","overrides":{"accountId":{"actor":"owner","attribute":"data-account-id","testid":"credit-panel"}},"testid":"credit-grant"},"namedAction":{"args":[0,1000,""],"id":"grantCredit","method":"POST","params":[{"in":"body","name":"accountId","wireType":"u64"},{"in":"body","name":"amountMinor"},{"in":"body","name":"reference"}],"path":"/api/staff/credit","reducer":"grant_credit"},"settleMs":0},{"actor":"staff","do":"expectActionOutcome","outcome":"accepted"},{"actor":"owner","do":"reload","settleMs":1000},{"actor":"owner","do":"ensureSignedIn","name":"credit-owner-753","readyTestid":"current-user"},{"actor":"owner","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"owner","do":"click","testid":"credit-link","unlessVisible":"credit-balance"},{"actor":"owner","do":"expectNumber","equals":10,"testid":"credit-balance","within":10000}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.store-credit","requiresFeatures":["ecommerce.feature.store-credit"],"role":"guarantee","source":"scenarios/progression-store-credit.json"},{"checkGroupId":"production-754","feature":{"actors":["owner","staff","tab"],"criteria":[{"id":"754a","steps":[{"action":"checkoutCredit","actors":["owner","tab"],"do":"callConcurrently","namedAction":{"args":[],"id":"checkoutCredit","method":"POST","path":"/api/checkout/credit","reducer":"checkout_credit"},"settleMs":0},{"do":"expectCallOutcomes"},{"actor":"owner","do":"freshClient"},{"actor":"owner-fresh","do":"signIn","name":"credit-owner-754"},{"actor":"owner-fresh","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"owner-fresh","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"owner-fresh","contains":"Desk Lamp","do":"expectElementCount","equals":1,"testid":"order-item","within":10000},{"actor":"owner-fresh","do":"expectNumber","equals":10,"in":{"contains":"Desk Lamp","testid":"order-item"},"testid":"payment-credit-amount"},{"actor":"owner-fresh","do":"expectNumber","equals":32,"in":{"contains":"Desk Lamp","testid":"order-item"},"testid":"payment-external-amount"},{"actor":"owner-fresh","do":"expectNumber","equals":42,"in":{"contains":"Desk Lamp","testid":"order-item"},"testid":"payment-amount"},{"actor":"owner-fresh","do":"click","testid":"credit-link","unlessVisible":"credit-panel"},{"actor":"owner-fresh","attribute":"aria-busy","do":"expect","testid":"credit-panel","value":"false","within":10000},{"actor":"owner-fresh","do":"expectNumber","equals":0,"testid":"credit-balance"}]}],"id":754,"setup":[{"actor":"owner","do":"signUp","name":"credit-owner-754"},{"actor":"owner","do":"click","testid":"credit-link","unlessVisible":"credit-panel"},{"actor":"owner","attribute":"aria-busy","do":"expect","testid":"credit-panel","value":"false","within":10000},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"staff","do":"click","testid":"credit-link","unlessVisible":"credit-panel"},{"actor":"staff","attribute":"aria-busy","do":"expect","testid":"credit-panel","value":"false","within":10000},{"actor":"staff","do":"fill","testid":"credit-amount-input","text":"10.00"},{"actor":"staff","do":"fill","testid":"credit-reference-input","text":"credit-754"},{"action":"grantCredit","actor":"staff","do":"callAction","from":"staff","input":{"attribute":"data-action-input","overrides":{"accountId":{"actor":"owner","attribute":"data-account-id","testid":"credit-panel"}},"testid":"credit-grant"},"namedAction":{"args":[0,1000,""],"id":"grantCredit","method":"POST","params":[{"in":"body","name":"accountId","wireType":"u64"},{"in":"body","name":"amountMinor"},{"in":"body","name":"reference"}],"path":"/api/staff/credit","reducer":"grant_credit"},"settleMs":0},{"actor":"staff","do":"expectActionOutcome","outcome":"accepted"},{"actor":"owner","do":"reload","settleMs":1000},{"actor":"owner","do":"ensureSignedIn","name":"credit-owner-754","readyTestid":"current-user"},{"actor":"owner","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"owner","do":"click","testid":"credit-link","unlessVisible":"credit-balance"},{"actor":"owner","do":"expectNumber","equals":10,"testid":"credit-balance","within":10000},{"actor":"owner","do":"click","testid":"catalog-link"},{"actor":"owner","do":"click","in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"add-to-cart"},{"actor":"owner","do":"click","testid":"cart-toggle"},{"actor":"owner","do":"expectNumber","equals":42,"testid":"cart-total"},{"actor":"tab","do":"signIn","name":"credit-owner-754"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.store-credit","requiresFeatures":["ecommerce.feature.store-credit"],"role":"guarantee","source":"scenarios/progression-store-credit.json"},{"checkGroupId":"production-755","feature":{"actors":["owner","staff","tab"],"criteria":[{"id":"755a","steps":[{"do":"restartBackend","settleMs":1000},{"actor":"owner","do":"freshClient"},{"actor":"owner-fresh","do":"signIn","name":"credit-owner-755"},{"actor":"owner-fresh","do":"click","testid":"credit-link","unlessVisible":"credit-panel"},{"actor":"owner-fresh","attribute":"aria-busy","do":"expect","testid":"credit-panel","value":"false","within":10000},{"actor":"owner-fresh","do":"expectNumber","equals":10,"testid":"credit-balance"}]}],"id":755,"setup":[{"actor":"owner","do":"signUp","name":"credit-owner-755"},{"actor":"owner","do":"click","testid":"credit-link","unlessVisible":"credit-panel"},{"actor":"owner","attribute":"aria-busy","do":"expect","testid":"credit-panel","value":"false","within":10000},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"staff","do":"click","testid":"credit-link","unlessVisible":"credit-panel"},{"actor":"staff","attribute":"aria-busy","do":"expect","testid":"credit-panel","value":"false","within":10000},{"actor":"staff","do":"fill","testid":"credit-amount-input","text":"10.00"},{"actor":"staff","do":"fill","testid":"credit-reference-input","text":"credit-755"},{"action":"grantCredit","actor":"staff","do":"callAction","from":"staff","input":{"attribute":"data-action-input","overrides":{"accountId":{"actor":"owner","attribute":"data-account-id","testid":"credit-panel"}},"testid":"credit-grant"},"namedAction":{"args":[0,1000,""],"id":"grantCredit","method":"POST","params":[{"in":"body","name":"accountId","wireType":"u64"},{"in":"body","name":"amountMinor"},{"in":"body","name":"reference"}],"path":"/api/staff/credit","reducer":"grant_credit"},"settleMs":0},{"actor":"staff","do":"expectActionOutcome","outcome":"accepted"},{"actor":"owner","do":"reload","settleMs":1000},{"actor":"owner","do":"ensureSignedIn","name":"credit-owner-755","readyTestid":"current-user"},{"actor":"owner","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"owner","do":"click","testid":"credit-link","unlessVisible":"credit-balance"},{"actor":"owner","do":"expectNumber","equals":10,"testid":"credit-balance","within":10000}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.store-credit","requiresFeatures":["ecommerce.feature.store-credit"],"role":"guarantee","source":"scenarios/progression-store-credit.json"}],"id":"selected-source-105","scenario":{"level":5,"writeUrlPattern":null},"source":"scenarios/progression-store-credit.json"},{"checkGroups":[{"checkGroupId":"subscriptions-760","feature":{"actors":["owner","other"],"criteria":[{"id":"760a","steps":[{"actor":"owner","do":"freshClient"},{"actor":"owner-fresh","do":"signIn","name":"subscription-760"},{"actor":"owner-fresh","do":"click","testid":"subscriptions-link","unlessVisible":"subscriptions-panel"},{"actor":"owner-fresh","attribute":"aria-busy","do":"expect","testid":"subscriptions-panel","value":"false","within":10000},{"actor":"owner-fresh","do":"expect","in":{"contains":"Desk Lamp","testid":"subscription-row"},"testid":"subscription-status","value":"complete","within":90000},{"actor":"owner-fresh","do":"expectElementCount","equals":2,"in":{"contains":"Desk Lamp","testid":"subscription-row"},"testid":"subscription-delivery"},{"actor":"owner-fresh","do":"expectSequence","equals":["paid","paid"],"in":{"contains":"Desk Lamp","testid":"subscription-row"},"testid":"subscription-delivery-status"},{"actor":"owner-fresh","do":"expectNumber","equals":84,"in":{"contains":"Desk Lamp","testid":"subscription-row"},"testid":"subscription-total"},{"do":"dbExpectStock","equals":8,"item":"Desk Lamp"},{"actor":"owner-fresh","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"owner-fresh","do":"click","testid":"orders-toggle"},{"actor":"owner-fresh","contains":"Desk Lamp","do":"expectElementCount","equals":2,"testid":"order-item","within":10000},{"actor":"owner-fresh","do":"expectElementCount","equals":2,"testid":"payment-record"}]}],"id":760,"setup":[{"actor":"owner","do":"signUp","name":"subscription-760"},{"do":"dbSetStock","item":"Desk Lamp","quantity":10,"settleMs":0,"warehouse":"East"},{"do":"dbSetStock","item":"Desk Lamp","quantity":0,"settleMs":0,"warehouse":"West"},{"actor":"owner","do":"click","testid":"subscriptions-link","unlessVisible":"subscriptions-panel"},{"actor":"owner","attribute":"aria-busy","do":"expect","testid":"subscriptions-panel","value":"false","within":10000},{"actor":"owner","do":"fill","testid":"subscription-item-input","text":"Desk Lamp"},{"actor":"owner","do":"fill","testid":"subscription-quantity-input","text":"1"},{"actor":"owner","do":"fill","testid":"subscription-interval-input","text":"30"},{"actor":"owner","do":"fill","testid":"subscription-deliveries-input","text":"2"},{"actor":"owner","do":"click","testid":"subscription-create"},{"actor":"owner","do":"expect","in":{"contains":"Desk Lamp","testid":"subscription-row"},"testid":"subscription-status","value":"active","within":10000}]},"packId":"ecommerce.feature.subscriptions","role":"feature","source":"scenarios/progression-subscriptions.json"},{"checkGroupId":"production-761","feature":{"actors":["owner","other"],"criteria":[{"id":"761a","steps":[{"do":"restartBackend","settleMs":1000},{"actor":"owner","do":"freshClient"},{"actor":"owner-fresh","do":"signIn","name":"subscription-761"},{"actor":"owner-fresh","do":"click","testid":"subscriptions-link","unlessVisible":"subscriptions-panel"},{"actor":"owner-fresh","attribute":"aria-busy","do":"expect","testid":"subscriptions-panel","value":"false","within":10000},{"actor":"owner-fresh","do":"expect","in":{"contains":"Desk Lamp","testid":"subscription-row"},"testid":"subscription-status","value":"complete","within":90000},{"actor":"owner-fresh","do":"expectElementCount","equals":2,"in":{"contains":"Desk Lamp","testid":"subscription-row"},"testid":"subscription-delivery"},{"actor":"owner-fresh","do":"expectSequence","equals":["paid","paid"],"in":{"contains":"Desk Lamp","testid":"subscription-row"},"testid":"subscription-delivery-status"},{"actor":"owner-fresh","do":"expectNumber","equals":84,"in":{"contains":"Desk Lamp","testid":"subscription-row"},"testid":"subscription-total"},{"do":"dbExpectStock","equals":8,"item":"Desk Lamp"},{"actor":"owner-fresh","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"owner-fresh","do":"click","testid":"orders-toggle"},{"actor":"owner-fresh","contains":"Desk Lamp","do":"expectElementCount","equals":2,"testid":"order-item","within":10000},{"actor":"owner-fresh","do":"expectElementCount","equals":2,"testid":"payment-record"},{"do":"restartBackend","settleMs":1000},{"actor":"owner","do":"freshClient"},{"actor":"owner-fresh","do":"signIn","name":"subscription-761"},{"actor":"owner-fresh","do":"click","testid":"subscriptions-link","unlessVisible":"subscriptions-panel"},{"actor":"owner-fresh","attribute":"aria-busy","do":"expect","testid":"subscriptions-panel","value":"false","within":10000},{"actor":"owner-fresh","do":"expect","in":{"contains":"Desk Lamp","testid":"subscription-row"},"testid":"subscription-status","value":"complete","within":90000},{"actor":"owner-fresh","do":"expectElementCount","equals":2,"in":{"contains":"Desk Lamp","testid":"subscription-row"},"testid":"subscription-delivery"},{"actor":"owner-fresh","do":"expectSequence","equals":["paid","paid"],"in":{"contains":"Desk Lamp","testid":"subscription-row"},"testid":"subscription-delivery-status"},{"actor":"owner-fresh","do":"expectNumber","equals":84,"in":{"contains":"Desk Lamp","testid":"subscription-row"},"testid":"subscription-total"},{"do":"dbExpectStock","equals":8,"item":"Desk Lamp"},{"actor":"owner-fresh","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"owner-fresh","do":"click","testid":"orders-toggle"},{"actor":"owner-fresh","contains":"Desk Lamp","do":"expectElementCount","equals":2,"testid":"order-item","within":10000},{"actor":"owner-fresh","do":"expectElementCount","equals":2,"testid":"payment-record"}]}],"id":761,"setup":[{"actor":"owner","do":"signUp","name":"subscription-761"},{"do":"dbSetStock","item":"Desk Lamp","quantity":10,"settleMs":0,"warehouse":"East"},{"do":"dbSetStock","item":"Desk Lamp","quantity":0,"settleMs":0,"warehouse":"West"},{"actor":"owner","do":"click","testid":"subscriptions-link","unlessVisible":"subscriptions-panel"},{"actor":"owner","attribute":"aria-busy","do":"expect","testid":"subscriptions-panel","value":"false","within":10000},{"actor":"owner","do":"fill","testid":"subscription-item-input","text":"Desk Lamp"},{"actor":"owner","do":"fill","testid":"subscription-quantity-input","text":"1"},{"actor":"owner","do":"fill","testid":"subscription-interval-input","text":"30"},{"actor":"owner","do":"fill","testid":"subscription-deliveries-input","text":"2"},{"actor":"owner","do":"click","testid":"subscription-create"},{"actor":"owner","do":"expect","in":{"contains":"Desk Lamp","testid":"subscription-row"},"testid":"subscription-status","value":"active","within":10000}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.subscriptions","requiresFeatures":["ecommerce.feature.subscriptions"],"role":"guarantee","source":"scenarios/progression-subscriptions.json"},{"checkGroupId":"production-762","feature":{"actors":["owner","other"],"criteria":[{"id":"762a","steps":[{"action":"cancelSubscription","actor":"other","do":"callAction","from":"owner","input":{"attribute":"data-action-input","testid":"subscription-cancel"},"namedAction":{"args":[0],"id":"cancelSubscription","method":"POST","params":[{"in":"path","name":"subscriptionId","placeholder":"{subscriptionId}","wireType":"u64"}],"path":"/api/subscriptions/{subscriptionId}/cancel","reducer":"cancel_subscription"},"settleMs":0},{"actor":"other","do":"expectActionOutcome","outcome":"refused"},{"actor":"owner","do":"expect","in":{"contains":"Desk Lamp","testid":"subscription-row"},"testid":"subscription-status","value":"active","within":10000},{"actor":"owner","do":"click","in":{"contains":"Desk Lamp","testid":"subscription-row"},"testid":"subscription-cancel"},{"actor":"owner","do":"freshClient"},{"actor":"owner-fresh","do":"signIn","name":"subscription-762"},{"actor":"owner-fresh","do":"click","testid":"subscriptions-link","unlessVisible":"subscriptions-panel"},{"actor":"owner-fresh","attribute":"aria-busy","do":"expect","testid":"subscriptions-panel","value":"false","within":10000},{"actor":"owner-fresh","do":"expect","in":{"contains":"Desk Lamp","testid":"subscription-row"},"testid":"subscription-status","value":"cancelled","within":10000},{"actor":"owner-fresh","as":"deliveries-at-cancel","count":true,"do":"recordNumber","in":{"contains":"Desk Lamp","testid":"subscription-row"},"testid":"subscription-delivery"},{"as":"stock-at-cancel","do":"dbRecordStock","item":"Desk Lamp"},{"actor":"owner-fresh","do":"wait","ms":65000},{"actor":"owner-fresh","do":"expectElementCount","in":{"contains":"Desk Lamp","testid":"subscription-row"},"plus":0,"relativeTo":"deliveries-at-cancel","testid":"subscription-delivery"},{"do":"dbExpectStock","item":"Desk Lamp","plus":0,"relativeTo":"stock-at-cancel"}]}],"id":762,"setup":[{"actor":"other","do":"signUp","name":"subscription-other-762"},{"actor":"owner","do":"signUp","name":"subscription-762"},{"do":"dbSetStock","item":"Desk Lamp","quantity":10,"settleMs":0,"warehouse":"East"},{"do":"dbSetStock","item":"Desk Lamp","quantity":0,"settleMs":0,"warehouse":"West"},{"actor":"owner","do":"click","testid":"subscriptions-link","unlessVisible":"subscriptions-panel"},{"actor":"owner","attribute":"aria-busy","do":"expect","testid":"subscriptions-panel","value":"false","within":10000},{"actor":"owner","do":"fill","testid":"subscription-item-input","text":"Desk Lamp"},{"actor":"owner","do":"fill","testid":"subscription-quantity-input","text":"1"},{"actor":"owner","do":"fill","testid":"subscription-interval-input","text":"30"},{"actor":"owner","do":"fill","testid":"subscription-deliveries-input","text":"2"},{"actor":"owner","do":"click","testid":"subscription-create"},{"actor":"owner","do":"expect","in":{"contains":"Desk Lamp","testid":"subscription-row"},"testid":"subscription-status","value":"active","within":10000}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.subscriptions","requiresFeatures":["ecommerce.feature.subscriptions"],"role":"guarantee","source":"scenarios/progression-subscriptions.json"},{"checkGroupId":"production-763","feature":{"actors":["owner","other"],"criteria":[{"id":"763a","steps":[{"actor":"owner","do":"click","in":{"contains":"Desk Lamp","testid":"subscription-row"},"testid":"subscription-pause"},{"actor":"owner","do":"expect","in":{"contains":"Desk Lamp","testid":"subscription-row"},"testid":"subscription-status","value":"paused","within":10000},{"do":"restartBackend","settleMs":1000},{"actor":"owner","do":"freshClient"},{"actor":"owner-fresh","do":"signIn","name":"subscription-763"},{"actor":"owner-fresh","do":"click","testid":"subscriptions-link","unlessVisible":"subscriptions-panel"},{"actor":"owner-fresh","attribute":"aria-busy","do":"expect","testid":"subscriptions-panel","value":"false","within":10000},{"actor":"owner-fresh","do":"expect","in":{"contains":"Desk Lamp","testid":"subscription-row"},"testid":"subscription-status","value":"paused","within":10000},{"actor":"owner-fresh","as":"deliveries-at-pause","count":true,"do":"recordNumber","in":{"contains":"Desk Lamp","testid":"subscription-row"},"testid":"subscription-delivery"},{"as":"stock-at-pause","do":"dbRecordStock","item":"Desk Lamp"},{"actor":"owner-fresh","do":"wait","ms":35000},{"actor":"owner-fresh","do":"expectElementCount","in":{"contains":"Desk Lamp","testid":"subscription-row"},"plus":0,"relativeTo":"deliveries-at-pause","testid":"subscription-delivery"},{"do":"dbExpectStock","item":"Desk Lamp","plus":0,"relativeTo":"stock-at-pause"},{"actor":"owner-fresh","do":"click","in":{"contains":"Desk Lamp","testid":"subscription-row"},"testid":"subscription-resume"},{"actor":"owner","do":"freshClient"},{"actor":"owner-fresh","do":"signIn","name":"subscription-763"},{"actor":"owner-fresh","do":"click","testid":"subscriptions-link","unlessVisible":"subscriptions-panel"},{"actor":"owner-fresh","attribute":"aria-busy","do":"expect","testid":"subscriptions-panel","value":"false","within":10000},{"actor":"owner-fresh","do":"expect","in":{"contains":"Desk Lamp","testid":"subscription-row"},"testid":"subscription-status","value":"complete","within":90000},{"actor":"owner-fresh","do":"expectElementCount","equals":2,"in":{"contains":"Desk Lamp","testid":"subscription-row"},"testid":"subscription-delivery"},{"actor":"owner-fresh","do":"expectSequence","equals":["paid","paid"],"in":{"contains":"Desk Lamp","testid":"subscription-row"},"testid":"subscription-delivery-status"},{"actor":"owner-fresh","do":"expectNumber","equals":84,"in":{"contains":"Desk Lamp","testid":"subscription-row"},"testid":"subscription-total"},{"do":"dbExpectStock","equals":8,"item":"Desk Lamp"},{"actor":"owner-fresh","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"owner-fresh","do":"click","testid":"orders-toggle"},{"actor":"owner-fresh","contains":"Desk Lamp","do":"expectElementCount","equals":2,"testid":"order-item","within":10000},{"actor":"owner-fresh","do":"expectElementCount","equals":2,"testid":"payment-record"}]}],"id":763,"setup":[{"actor":"owner","do":"signUp","name":"subscription-763"},{"do":"dbSetStock","item":"Desk Lamp","quantity":10,"settleMs":0,"warehouse":"East"},{"do":"dbSetStock","item":"Desk Lamp","quantity":0,"settleMs":0,"warehouse":"West"},{"actor":"owner","do":"click","testid":"subscriptions-link","unlessVisible":"subscriptions-panel"},{"actor":"owner","attribute":"aria-busy","do":"expect","testid":"subscriptions-panel","value":"false","within":10000},{"actor":"owner","do":"fill","testid":"subscription-item-input","text":"Desk Lamp"},{"actor":"owner","do":"fill","testid":"subscription-quantity-input","text":"1"},{"actor":"owner","do":"fill","testid":"subscription-interval-input","text":"30"},{"actor":"owner","do":"fill","testid":"subscription-deliveries-input","text":"2"},{"actor":"owner","do":"click","testid":"subscription-create"},{"actor":"owner","do":"expect","in":{"contains":"Desk Lamp","testid":"subscription-row"},"testid":"subscription-status","value":"active","within":10000}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.subscriptions","requiresFeatures":["ecommerce.feature.subscriptions"],"role":"guarantee","source":"scenarios/progression-subscriptions.json"}],"id":"selected-source-106","scenario":{"level":5,"writeUrlPattern":null},"source":"scenarios/progression-subscriptions.json"},{"checkGroups":[{"checkGroupId":"support-history","feature":{"actors":["owner","other"],"criteria":[{"id":"612c","steps":[{"actor":"owner","do":"reload","settleMs":1000},{"actor":"owner","do":"ensureSignedIn","name":"support-owner","readyTestid":"current-user"},{"actor":"owner","do":"click","testid":"support-link","unlessVisible":"support-ticket"},{"actor":"owner","contains":"Owner ticket {user:ticketmarker}","do":"expect","testid":"support-ticket"}]}],"id":612,"setup":[{"actor":"owner","do":"signUp","name":"support-owner"},{"actor":"owner","do":"click","testid":"support-link"},{"actor":"owner","do":"fill","testid":"support-email","text":"owner@example.com"},{"actor":"owner","do":"fill","testid":"support-subject","text":"Owner ticket {user:ticketmarker}"},{"actor":"owner","do":"fill","testid":"support-message","text":"Private account issue."},{"actor":"owner","do":"click","testid":"support-submit"},{"actor":"owner","do":"expect","nonEmpty":true,"testid":"support-reference"},{"actor":"other","do":"signUp","name":"support-other"}]},"packId":"ecommerce.progression.support-history","role":"feature","source":"scenarios/progression-support-history.json"},{"checkGroupId":"support-history-reload","feature":{"actors":["owner","other"],"criteria":[{"id":"612a","steps":[{"actor":"owner","do":"reload","settleMs":3000},{"actor":"owner","do":"ensureSignedIn","name":"support-owner","readyTestid":"current-user"},{"actor":"owner","do":"click","testid":"support-link"},{"actor":"owner","contains":"Owner ticket {user:ticketmarker}","do":"expect","testid":"support-ticket"},{"do":"restartBackend","settleMs":1000},{"actor":"owner","do":"freshClient"},{"actor":"owner-fresh","do":"signIn","name":"support-owner"},{"actor":"owner-fresh","do":"click","testid":"support-link"},{"actor":"owner-fresh","contains":"Owner ticket {user:ticketmarker}","do":"expect","testid":"support-ticket"}]}],"id":612,"setup":[{"actor":"owner","do":"signUp","name":"support-owner"},{"actor":"owner","do":"click","testid":"support-link"},{"actor":"owner","do":"fill","testid":"support-email","text":"owner@example.com"},{"actor":"owner","do":"fill","testid":"support-subject","text":"Owner ticket {user:ticketmarker}"},{"actor":"owner","do":"fill","testid":"support-message","text":"Private account issue."},{"actor":"owner","do":"click","testid":"support-submit"},{"actor":"owner","do":"expect","nonEmpty":true,"testid":"support-reference"},{"actor":"other","do":"signUp","name":"support-other"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.state-durability","requiresFeatures":["ecommerce.progression.support-history"],"role":"guarantee","source":"scenarios/progression-support-history.json"},{"checkGroupId":"support-history-privacy","feature":{"actors":["owner","other"],"criteria":[{"id":"612b","steps":[{"actor":"owner","do":"reload","settleMs":1000},{"actor":"owner","do":"ensureSignedIn","name":"support-owner","readyTestid":"current-user"},{"actor":"owner","do":"click","testid":"support-link"},{"actor":"owner","do":"fill","testid":"support-email","text":"owner@example.com"},{"actor":"owner","do":"fill","testid":"support-subject","text":"Private ticket {user:privateticketmarker}"},{"actor":"owner","do":"fill","testid":"support-message","text":"Private account issue."},{"actor":"owner","do":"click","testid":"support-submit"},{"actor":"owner","do":"expect","nonEmpty":true,"testid":"support-reference"},{"actor":"owner","do":"reload","settleMs":1000},{"actor":"owner","do":"ensureSignedIn","name":"support-owner","readyTestid":"current-user"},{"actor":"owner","do":"click","testid":"support-link"},{"actor":"owner","contains":"Private ticket {user:privateticketmarker}","do":"expect","testid":"support-ticket"},{"actor":"owner","contains":"Private ticket {user:privateticketmarker}","do":"expectReceived","within":10000},{"actor":"other","do":"reload","settleMs":0},{"actor":"other","do":"ensureSignedIn","name":"support-other","readyTestid":"current-user"},{"actor":"other","do":"click","testid":"support-link"},{"absent":true,"actor":"other","contains":"Private ticket {user:privateticketmarker}","do":"expect","testid":"support-ticket"},{"actor":"other","contains":"Private ticket {user:privateticketmarker}","do":"expectNotReceived"}]}],"id":612,"setup":[{"actor":"owner","do":"signUp","name":"support-owner"},{"actor":"owner","do":"click","testid":"support-link"},{"actor":"owner","do":"fill","testid":"support-email","text":"owner@example.com"},{"actor":"owner","do":"fill","testid":"support-subject","text":"Owner ticket {user:ticketmarker}"},{"actor":"owner","do":"fill","testid":"support-message","text":"Private account issue."},{"actor":"owner","do":"click","testid":"support-submit"},{"actor":"owner","do":"expect","nonEmpty":true,"testid":"support-reference"},{"actor":"other","do":"signUp","name":"support-other"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","requiresFeatures":["ecommerce.progression.support-history"],"role":"guarantee","source":"scenarios/progression-support-history.json"},{"checkGroupId":"support-history-logout","feature":{"actors":["owner","other"],"criteria":[{"id":"612d","steps":[{"actor":"owner","do":"reload","settleMs":1000},{"actor":"owner","do":"ensureSignedIn","name":"support-owner","readyTestid":"current-user"},{"actor":"owner","do":"click","testid":"support-link"},{"actor":"owner","do":"fill","testid":"support-email","text":"owner@example.com"},{"actor":"owner","do":"fill","testid":"support-subject","text":"Logout ticket {user:logoutticketmarker}"},{"actor":"owner","do":"fill","testid":"support-message","text":"Private account issue."},{"actor":"owner","do":"click","testid":"support-submit"},{"actor":"owner","do":"expect","nonEmpty":true,"testid":"support-reference"},{"actor":"owner","do":"reload","settleMs":1000},{"actor":"owner","do":"ensureSignedIn","name":"support-owner","readyTestid":"current-user"},{"actor":"owner","do":"click","testid":"support-link","unlessVisible":"support-ticket"},{"actor":"owner","contains":"Logout ticket {user:logoutticketmarker}","do":"expect","testid":"support-ticket"},{"actor":"owner","contains":"Logout ticket {user:logoutticketmarker}","do":"expectReceived","within":10000},{"actor":"owner","do":"reload","settleMs":1000},{"actor":"owner","do":"ensureSignedIn","name":"support-owner","readyTestid":"current-user"},{"actor":"owner","do":"click","testid":"current-user","unlessVisible":"signout"},{"actor":"owner","do":"click","testid":"signout"},{"actor":"owner","do":"waitUntilAbsent","testid":"current-user","within":6000},{"actor":"owner","do":"freshClient","preserveStorage":true},{"absent":true,"actor":"owner-fresh","do":"expect","testid":"current-user"},{"actor":"owner-fresh","do":"click","testid":"support-link"},{"actor":"owner-fresh","do":"expect","testid":"support-email"},{"absent":true,"actor":"owner-fresh","contains":"Logout ticket {user:logoutticketmarker}","do":"expect","testid":"support-ticket"},{"actor":"owner-fresh","contains":"Logout ticket {user:logoutticketmarker}","do":"expectNotReceived"}]}],"id":612,"setup":[{"actor":"owner","do":"signUp","name":"support-owner"},{"actor":"owner","do":"click","testid":"support-link"},{"actor":"owner","do":"fill","testid":"support-email","text":"owner@example.com"},{"actor":"owner","do":"fill","testid":"support-subject","text":"Owner ticket {user:ticketmarker}"},{"actor":"owner","do":"fill","testid":"support-message","text":"Private account issue."},{"actor":"owner","do":"click","testid":"support-submit"},{"actor":"owner","do":"expect","nonEmpty":true,"testid":"support-reference"},{"actor":"other","do":"signUp","name":"support-other"}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","requiresFeatures":["ecommerce.progression.support-history"],"role":"guarantee","source":"scenarios/progression-support-history.json"}],"id":"selected-source-107","scenario":{"level":2,"writeUrlPattern":null},"source":"scenarios/progression-support-history.json"},{"checkGroups":[{"checkGroupId":"support-intake","feature":{"actors":["visitor"],"criteria":[{"id":"610a","steps":[{"actor":"visitor","do":"click","testid":"support-link"},{"actor":"visitor","do":"fill","testid":"support-email","text":"visitor@example.com"},{"actor":"visitor","do":"fill","testid":"support-subject","text":"Damaged package"},{"actor":"visitor","do":"fill","testid":"support-message","text":"The package arrived damaged."},{"actor":"visitor","do":"click","testid":"support-submit"},{"actor":"visitor","do":"expect","nonEmpty":true,"testid":"support-reference"}]}],"id":610,"setup":[]},"packId":"ecommerce.progression.support-intake","role":"feature","source":"scenarios/progression-support-intake.json"}],"id":"selected-source-108","scenario":{"level":1,"writeUrlPattern":null},"source":"scenarios/progression-support-intake.json"},{"checkGroups":[{"checkGroupId":"support-refund-access","feature":{"actors":["owner","staff"],"criteria":[{"id":"615c","steps":[{"absent":true,"actor":"owner","do":"expect","testid":"support-refund"},{"action":"supportRefund","actor":"owner","authentication":"actor","do":"callAction","from":"staff","input":{"attribute":"data-action-input","testid":"support-refund"},"namedAction":{"args":[0],"id":"supportRefund","method":"POST","params":[{"in":"path","name":"caseId","placeholder":"{caseId}","wireType":"u64"}],"path":"/api/support/cases/{caseId}/refund","reducer":"support_refund"},"settleMs":1500},{"actor":"owner","do":"expectActionOutcome","outcome":"refused"},{"actor":"owner","do":"reload","settleMs":1000},{"actor":"owner","do":"ensureSignedIn","name":"refund-access-owner","readyTestid":"current-user"},{"actor":"owner","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"owner","do":"click","testid":"support-link","unlessVisible":"support-subject"},{"actor":"owner","do":"expect","in":{"contains":"Access refund case","testid":"support-ticket"},"notContains":"resolved","testid":"support-status"},{"actor":"owner","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"owner","do":"click","testid":"orders-toggle"},{"actor":"owner","do":"expect","in":{"contains":"Keyboard","testid":"order-item"},"testid":"order-status","value":"pending"},{"absent":true,"actor":"owner","contains":"Keyboard","do":"expect","testid":"refund-entry"}]}],"id":615,"setup":[{"actor":"owner","do":"signUp","name":"refund-access-owner"},{"actor":"owner","do":"click","in":{"contains":"Keyboard","testid":"item-card"},"testid":"buy-now"},{"actor":"owner","do":"click","testid":"support-link"},{"actor":"owner","do":"fill","testid":"support-subject","text":"Access refund case"},{"actor":"owner","do":"fill","testid":"support-message","text":"This refund requires staff approval."},{"actor":"owner","do":"click","testid":"support-submit"},{"actor":"owner","contains":"Keyboard","do":"click","in":{"contains":"Access refund case","testid":"support-ticket"},"testid":"support-order-option"},{"actor":"owner","do":"click","in":{"contains":"Access refund case","testid":"support-ticket"},"testid":"support-link-order"},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"staff","do":"click","testid":"staff-link","unlessVisible":"support-assignee"},{"actor":"staff","do":"click","ifAvailable":true,"testid":"support-queue-link","unlessVisible":"support-assignee","within":1000}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.access-control","requiresFeatures":["ecommerce.progression.support-refunds"],"role":"guarantee","source":"scenarios/progression-support-refunds-access.json"}],"id":"selected-source-109","scenario":{"level":5,"writeUrlPattern":null},"source":"scenarios/progression-support-refunds-access.json"},{"checkGroups":[{"checkGroupId":"support-refund-accounting","feature":{"actors":["owner","staff"],"criteria":[{"id":"615b","steps":[{"actor":"staff","do":"click","in":{"contains":"Accounting refund case","testid":"support-ticket"},"testid":"support-refund"},{"actor":"owner","do":"reload","settleMs":1000},{"actor":"owner","do":"ensureSignedIn","name":"refund-accounting-owner","readyTestid":"current-user"},{"actor":"owner","do":"click","ifAvailable":true,"testid":"overlay-close","within":1000},{"actor":"owner","do":"click","testid":"support-link","unlessVisible":"support-subject"},{"actor":"owner","do":"expectNumber","in":{"contains":"Accounting refund case","testid":"support-ticket"},"plus":0,"relativeTo":"paid-total","testid":"support-refund-total","within":10000},{"actor":"owner","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"owner","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"owner","do":"expectNumber","in":{"contains":"Keyboard","testid":"order-item"},"plus":0,"relativeTo":"paid-total","testid":"order-refund-total","within":10000},{"actor":"owner","contains":"Keyboard","do":"expectElementCount","equals":1,"testid":"refund-entry","within":10000},{"actor":"staff","do":"replayAs","from":"staff","match":"refund","namedAction":{"args":[0],"id":"supportRefund","method":"POST","params":[{"in":"path","name":"caseId","placeholder":"{caseId}","wireType":"u64"}],"path":"/api/support/cases/{caseId}/refund","reducer":"support_refund"},"namedTarget":{"attribute":"data-entity-id","contains":"Accounting refund case","testid":"support-ticket","valueType":"string"},"settleMs":1500},{"actor":"staff","do":"expectReplayCompleted"},{"actor":"owner","do":"freshClient"},{"actor":"owner-fresh","do":"signIn","name":"refund-accounting-owner"},{"actor":"owner-fresh","do":"click","testid":"support-link"},{"actor":"owner-fresh","do":"expectNumber","in":{"contains":"Accounting refund case","testid":"support-ticket"},"plus":0,"relativeTo":"paid-total","testid":"support-refund-total","within":10000},{"actor":"owner-fresh","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"owner-fresh","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"owner-fresh","do":"expectNumber","in":{"contains":"Keyboard","testid":"order-item"},"plus":0,"relativeTo":"paid-total","testid":"order-refund-total","within":10000},{"actor":"owner-fresh","contains":"Keyboard","do":"expectElementCount","equals":1,"testid":"refund-entry","within":10000},{"actor":"owner-fresh","do":"expectNumber","equals":0,"in":{"contains":"Mouse","testid":"order-item"},"testid":"order-refund-total","within":10000},{"actor":"owner-fresh","contains":"Mouse","do":"expectElementCount","equals":0,"testid":"refund-entry","within":10000}]}],"id":615,"setup":[{"actor":"owner","do":"signUp","name":"refund-accounting-owner"},{"actor":"owner","do":"click","in":{"contains":"Mouse","testid":"item-card"},"testid":"buy-now"},{"actor":"owner","do":"click","in":{"contains":"Keyboard","testid":"item-card"},"testid":"buy-now"},{"actor":"owner","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"owner","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"owner","as":"paid-total","do":"recordNumber","in":{"contains":"Keyboard","testid":"order-item"},"testid":"order-total"},{"actor":"owner","do":"click","testid":"support-link"},{"actor":"owner","do":"fill","testid":"support-subject","text":"Accounting refund case"},{"actor":"owner","do":"fill","testid":"support-message","text":"Refund the exact amount paid."},{"actor":"owner","do":"click","testid":"support-submit"},{"actor":"owner","contains":"Keyboard","do":"click","in":{"contains":"Accounting refund case","testid":"support-ticket"},"testid":"support-order-option"},{"actor":"owner","do":"click","in":{"contains":"Accounting refund case","testid":"support-ticket"},"testid":"support-link-order"},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"staff","do":"click","testid":"staff-link","unlessVisible":"support-assignee"},{"actor":"staff","do":"click","ifAvailable":true,"testid":"support-queue-link","unlessVisible":"support-assignee","within":1000}]},"observations":["requested","unmentioned"],"packId":"ecommerce.spec.transactional-integrity","requiresFeatures":["ecommerce.progression.support-refunds"],"role":"guarantee","source":"scenarios/progression-support-refunds-accounting.json"}],"id":"selected-source-110","scenario":{"level":5,"writeUrlPattern":null},"source":"scenarios/progression-support-refunds-accounting.json"},{"checkGroups":[{"checkGroupId":"support-refunds-resolution","feature":{"actors":["owner","staff"],"criteria":[{"id":"615a","steps":[{"actor":"staff","do":"click","in":{"contains":"Resolution refund case","testid":"support-ticket"},"testid":"support-refund"},{"actor":"owner","contains":"resolved","do":"expect","in":{"contains":"Resolution refund case","testid":"support-ticket"},"testid":"support-status","within":10000},{"actor":"owner","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"owner","do":"click","testid":"orders-toggle"},{"actor":"owner","contains":"refunded","do":"expect","in":{"contains":"Keyboard","testid":"order-item"},"testid":"order-status","within":10000}]}],"id":615,"setup":[{"actor":"owner","do":"signUp","name":"refund-resolution-owner"},{"actor":"owner","do":"click","in":{"contains":"Keyboard","testid":"item-card"},"testid":"buy-now"},{"actor":"owner","do":"click","testid":"support-link"},{"actor":"owner","do":"fill","testid":"support-subject","text":"Resolution refund case"},{"actor":"owner","do":"fill","testid":"support-message","text":"Please refund my Keyboard order."},{"actor":"owner","do":"click","testid":"support-submit"},{"actor":"owner","contains":"Keyboard","do":"click","in":{"contains":"Resolution refund case","testid":"support-ticket"},"testid":"support-order-option"},{"actor":"owner","do":"click","in":{"contains":"Resolution refund case","testid":"support-ticket"},"testid":"support-link-order"},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"staff","do":"click","testid":"staff-link","unlessVisible":"support-assignee"},{"actor":"staff","do":"click","ifAvailable":true,"testid":"support-queue-link","unlessVisible":"support-assignee"}]},"packId":"ecommerce.progression.support-refunds","role":"feature","source":"scenarios/progression-support-refunds-resolution.json"}],"id":"selected-source-111","scenario":{"level":5,"writeUrlPattern":null},"source":"scenarios/progression-support-refunds-resolution.json"},{"checkGroups":[{"checkGroupId":"return-refund-interaction","feature":{"actors":["owner","staff","admin"],"criteria":[{"id":"757a","steps":[{"actor":"owner","do":"reload","settleMs":0},{"actor":"owner","do":"ensureSignedIn","name":"return-refund-owner","readyTestid":"current-user","settleMs":0},{"actor":"owner","do":"click","ifAvailable":true,"testid":"catalog-link"},{"as":"757atotal","do":"dbRecordStock","item":"Keyboard"},{"as":"757aEast","do":"dbRecordStock","item":"Keyboard","warehouse":"East"},{"as":"757aWest","do":"dbRecordStock","item":"Keyboard","warehouse":"West"},{"actor":"admin","as":"757arevenue","do":"recordNumber","testid":"admin-revenue"},{"actor":"owner","do":"click","in":{"contains":"Keyboard","testid":"item-card"},"testid":"buy-now"},{"actor":"owner","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"owner","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"owner","do":"expect","ignoreCase":true,"in":{"contains":"Keyboard","testid":"order-item"},"testid":"order-status","value":"pending","within":10000},{"actor":"owner","as":"757apaid","do":"recordNumber","in":{"contains":"Keyboard","testid":"order-item"},"testid":"order-total"},{"action":"ship","actor":"staff","do":"callAction","from":"owner","input":{"attribute":"data-ship-input","contains":"Keyboard","testid":"order-item"},"namedAction":{"args":[0],"id":"ship","params":[{"in":"body","name":"orderId","wireType":"u64"}],"path":"/api/fulfilment/ship","reducer":"ship_order"},"settleMs":0},{"actor":"staff","do":"expectActionOutcome","outcome":"accepted"},{"actor":"owner","do":"expect","ignoreCase":true,"in":{"contains":"Keyboard","testid":"order-item"},"testid":"order-status","value":"shipped","within":10000},{"do":"dbExpectStock","item":"Keyboard","plus":-1,"relativeTo":"757atotal"},{"actor":"owner","do":"reload","settleMs":0},{"actor":"owner","do":"ensureSignedIn","name":"return-refund-owner","readyTestid":"current-user","settleMs":0},{"actor":"owner","do":"click","testid":"support-link"},{"actor":"owner","do":"fill","testid":"support-subject","text":"Return refund 757a"},{"actor":"owner","do":"fill","testid":"support-message","text":"Please refund this order."},{"actor":"owner","do":"click","testid":"support-submit"},{"actor":"owner","contains":"Return refund 757a","do":"expect","testid":"support-ticket","within":10000},{"actor":"owner","contains":"Keyboard","do":"click","in":{"contains":"Return refund 757a","testid":"support-ticket"},"testid":"support-order-option"},{"actor":"owner","do":"click","in":{"contains":"Return refund 757a","testid":"support-ticket"},"testid":"support-link-order"},{"actor":"owner","do":"expect","in":{"contains":"Return refund 757a","testid":"support-ticket"},"testid":"support-order","within":10000},{"action":"supportRefund","actor":"staff","do":"callAction","from":"owner","input":{"attribute":"data-refund-input","contains":"Return refund 757a","testid":"support-ticket"},"namedAction":{"args":[0],"id":"supportRefund","method":"POST","params":[{"in":"path","name":"caseId","placeholder":"{caseId}","wireType":"u64"}],"path":"/api/support/cases/{caseId}/refund","reducer":"support_refund"},"settleMs":0},{"actor":"staff","do":"expectActionOutcome","outcome":"accepted"},{"do":"dbExpectStock","item":"Keyboard","plus":-1,"relativeTo":"757atotal"},{"actor":"owner","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"owner","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"owner","do":"click","in":{"contains":"Keyboard","testid":"order-item"},"testid":"return-item"},{"actor":"owner","contains":"Keyboard","containsText":"returned","do":"expect","ignoreCase":true,"testid":"order-item","within":10000},{"actor":"owner","do":"freshClient"},{"actor":"owner-fresh","do":"signIn","name":"return-refund-owner"},{"actor":"owner-fresh","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"owner-fresh","do":"click","testid":"orders-toggle"},{"actor":"owner-fresh","contains":"Keyboard","containsText":"returned","do":"expect","ignoreCase":true,"testid":"order-item","within":10000},{"actor":"owner-fresh","do":"expectNumber","in":{"contains":"Keyboard","testid":"order-item"},"plus":0,"relativeTo":"757apaid","testid":"order-refund-total","within":10000},{"do":"dbExpectStock","item":"Keyboard","plus":0,"relativeTo":"757aEast","warehouse":"East"},{"do":"dbExpectStock","item":"Keyboard","plus":0,"relativeTo":"757aWest","warehouse":"West"},{"actor":"admin","do":"reload","settleMs":0},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","testid":"admin-link","unlessVisible":"admin-revenue"},{"actor":"admin","do":"expectNumber","plus":0,"relativeTo":"757arevenue","testid":"admin-revenue","within":10000}]},{"id":"757b","steps":[{"actor":"owner","do":"reload","settleMs":0},{"actor":"owner","do":"ensureSignedIn","name":"return-refund-owner","readyTestid":"current-user","settleMs":0},{"actor":"owner","do":"click","ifAvailable":true,"testid":"catalog-link"},{"as":"757btotal","do":"dbRecordStock","item":"Desk Lamp"},{"as":"757bEast","do":"dbRecordStock","item":"Desk Lamp","warehouse":"East"},{"as":"757bWest","do":"dbRecordStock","item":"Desk Lamp","warehouse":"West"},{"actor":"admin","as":"757brevenue","do":"recordNumber","testid":"admin-revenue"},{"actor":"owner","do":"click","in":{"contains":"Desk Lamp","testid":"item-card"},"testid":"buy-now"},{"actor":"owner","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"owner","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"owner","do":"expect","ignoreCase":true,"in":{"contains":"Desk Lamp","testid":"order-item"},"testid":"order-status","value":"pending","within":10000},{"actor":"owner","as":"757bpaid","do":"recordNumber","in":{"contains":"Desk Lamp","testid":"order-item"},"testid":"order-total"},{"action":"ship","actor":"staff","do":"callAction","from":"owner","input":{"attribute":"data-ship-input","contains":"Desk Lamp","testid":"order-item"},"namedAction":{"args":[0],"id":"ship","params":[{"in":"body","name":"orderId","wireType":"u64"}],"path":"/api/fulfilment/ship","reducer":"ship_order"},"settleMs":0},{"actor":"staff","do":"expectActionOutcome","outcome":"accepted"},{"actor":"owner","do":"expect","ignoreCase":true,"in":{"contains":"Desk Lamp","testid":"order-item"},"testid":"order-status","value":"shipped","within":10000},{"do":"dbExpectStock","item":"Desk Lamp","plus":-1,"relativeTo":"757btotal"},{"actor":"owner","do":"reload","settleMs":0},{"actor":"owner","do":"ensureSignedIn","name":"return-refund-owner","readyTestid":"current-user","settleMs":0},{"actor":"owner","do":"click","testid":"support-link"},{"actor":"owner","do":"fill","testid":"support-subject","text":"Return refund 757b"},{"actor":"owner","do":"fill","testid":"support-message","text":"Please refund this order."},{"actor":"owner","do":"click","testid":"support-submit"},{"actor":"owner","contains":"Return refund 757b","do":"expect","testid":"support-ticket","within":10000},{"actor":"owner","contains":"Desk Lamp","do":"click","in":{"contains":"Return refund 757b","testid":"support-ticket"},"testid":"support-order-option"},{"actor":"owner","do":"click","in":{"contains":"Return refund 757b","testid":"support-ticket"},"testid":"support-link-order"},{"actor":"owner","do":"expect","in":{"contains":"Return refund 757b","testid":"support-ticket"},"testid":"support-order","within":10000},{"actor":"owner","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"owner","do":"click","testid":"orders-toggle","unlessVisible":"order-item"},{"actor":"owner","do":"click","in":{"contains":"Desk Lamp","testid":"order-item"},"testid":"return-item"},{"actor":"owner","contains":"Desk Lamp","containsText":"returned","do":"expect","ignoreCase":true,"testid":"order-item","within":10000},{"action":"supportRefund","actor":"staff","do":"callAction","from":"owner","input":{"attribute":"data-refund-input","contains":"Return refund 757b","testid":"support-ticket"},"namedAction":{"args":[0],"id":"supportRefund","method":"POST","params":[{"in":"path","name":"caseId","placeholder":"{caseId}","wireType":"u64"}],"path":"/api/support/cases/{caseId}/refund","reducer":"support_refund"},"settleMs":0},{"actor":"staff","do":"expectActionOutcome","outcome":"accepted"},{"actor":"owner","do":"freshClient"},{"actor":"owner-fresh","do":"signIn","name":"return-refund-owner"},{"actor":"owner-fresh","do":"click","ifAvailable":true,"testid":"overlay-close","unlessVisible":"order-item","within":1000},{"actor":"owner-fresh","do":"click","testid":"orders-toggle"},{"actor":"owner-fresh","contains":"Desk Lamp","containsText":"returned","do":"expect","ignoreCase":true,"testid":"order-item","within":10000},{"actor":"owner-fresh","do":"expectNumber","in":{"contains":"Desk Lamp","testid":"order-item"},"plus":0,"relativeTo":"757bpaid","testid":"order-refund-total","within":10000},{"do":"dbExpectStock","item":"Desk Lamp","plus":0,"relativeTo":"757bEast","warehouse":"East"},{"do":"dbExpectStock","item":"Desk Lamp","plus":0,"relativeTo":"757bWest","warehouse":"West"},{"actor":"admin","do":"reload","settleMs":0},{"actor":"admin","do":"ensureSignedIn","exact":true,"name":"admin","password":"stackbench-admin-2026","readyTestid":"current-user"},{"actor":"admin","do":"click","testid":"admin-link","unlessVisible":"admin-revenue"},{"actor":"admin","do":"expectNumber","plus":0,"relativeTo":"757brevenue","testid":"admin-revenue","within":10000}]}],"id":757,"setup":[{"actor":"owner","do":"signUp","name":"return-refund-owner"},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"admin","do":"signIn","exact":true,"name":"admin","password":"stackbench-admin-2026"},{"actor":"staff","do":"click","testid":"staff-link","unlessVisible":"support-assignee"},{"actor":"staff","do":"click","ifAvailable":true,"testid":"support-queue-link","unlessVisible":"support-assignee"},{"actor":"admin","do":"click","testid":"admin-link"}]},"packId":"ecommerce.feature.split-tender-refunds","requiresFeatures":["ecommerce.l3.order-returns-features","ecommerce.progression.fulfilment-queue","ecommerce.progression.support-refunds"],"role":"feature","source":"scenarios/progression-support-return-interaction.json"}],"id":"selected-source-112","scenario":{"level":6,"writeUrlPattern":null},"source":"scenarios/progression-support-return-interaction.json"},{"checkGroups":[{"checkGroupId":"support-assignment","feature":{"actors":["visitor","staff"],"criteria":[{"id":"611a","steps":[{"actor":"staff","do":"fill","in":{"contains":"Missing item","testid":"support-ticket"},"testid":"support-assignee","text":"staff"},{"actor":"staff","do":"click","in":{"contains":"Missing item","testid":"support-ticket"},"settleMs":1500,"testid":"support-update"},{"actor":"staff","do":"reload","settleMs":2500},{"actor":"staff","do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026","readyTestid":"current-user"},{"actor":"staff","do":"click","ifAvailable":true,"testid":"staff-link","unlessVisible":"support-assignee"},{"actor":"staff","do":"click","ifAvailable":true,"testid":"support-queue-link","unlessVisible":"support-assignee"},{"actor":"staff","do":"expect","in":{"contains":"Missing item","testid":"support-ticket"},"testid":"support-assignee","value":"staff"}]}],"id":611,"setup":[{"actor":"visitor","do":"click","testid":"support-link"},{"actor":"visitor","do":"fill","testid":"support-email","text":"triage@example.com"},{"actor":"visitor","do":"fill","testid":"support-subject","text":"Missing item"},{"actor":"visitor","do":"fill","testid":"support-message","text":"One item is missing."},{"actor":"visitor","do":"click","testid":"support-submit"},{"actor":"visitor","do":"expect","nonEmpty":true,"testid":"support-reference"},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"staff","do":"click","testid":"staff-link","unlessVisible":"support-assignee"},{"actor":"staff","do":"click","ifAvailable":true,"testid":"support-queue-link","unlessVisible":"support-assignee"}]},"packId":"ecommerce.progression.support-triage","role":"feature","source":"scenarios/progression-support-triage.json"},{"checkGroupId":"support-priority","feature":{"actors":["visitor","staff"],"criteria":[{"id":"611b","steps":[{"actor":"staff","do":"fill","in":{"contains":"Missing item","testid":"support-ticket"},"testid":"support-priority","text":"high"},{"actor":"staff","do":"click","in":{"contains":"Missing item","testid":"support-ticket"},"settleMs":1500,"testid":"support-update"},{"actor":"staff","do":"reload","settleMs":2500},{"actor":"staff","do":"ensureSignedIn","exact":true,"name":"staff","password":"stackbench-staff-2026","readyTestid":"current-user"},{"actor":"staff","do":"click","ifAvailable":true,"testid":"staff-link","unlessVisible":"support-assignee"},{"actor":"staff","do":"click","ifAvailable":true,"testid":"support-queue-link","unlessVisible":"support-assignee"},{"actor":"staff","do":"expect","in":{"contains":"Missing item","testid":"support-ticket"},"testid":"support-priority","value":"high"}]}],"id":611,"setup":[{"actor":"visitor","do":"click","testid":"support-link"},{"actor":"visitor","do":"fill","testid":"support-email","text":"triage@example.com"},{"actor":"visitor","do":"fill","testid":"support-subject","text":"Missing item"},{"actor":"visitor","do":"fill","testid":"support-message","text":"One item is missing."},{"actor":"visitor","do":"click","testid":"support-submit"},{"actor":"visitor","do":"expect","nonEmpty":true,"testid":"support-reference"},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"staff","do":"click","testid":"staff-link","unlessVisible":"support-assignee"},{"actor":"staff","do":"click","ifAvailable":true,"testid":"support-queue-link","unlessVisible":"support-assignee"}]},"packId":"ecommerce.progression.support-triage","role":"feature","source":"scenarios/progression-support-triage.json"},{"checkGroupId":"support-status","feature":{"actors":["visitor","staff"],"criteria":[{"id":"611c","steps":[{"actor":"staff","do":"fill","in":{"contains":"Missing item","testid":"support-ticket"},"testid":"support-status-input","text":"in progress"},{"actor":"staff","do":"click","in":{"contains":"Missing item","testid":"support-ticket"},"settleMs":1500,"testid":"support-update"},{"actor":"staff","contains":"in progress","do":"expect","in":{"contains":"Missing item","testid":"support-ticket"},"testid":"support-status"}]}],"id":611,"setup":[{"actor":"visitor","do":"click","testid":"support-link"},{"actor":"visitor","do":"fill","testid":"support-email","text":"triage@example.com"},{"actor":"visitor","do":"fill","testid":"support-subject","text":"Missing item"},{"actor":"visitor","do":"fill","testid":"support-message","text":"One item is missing."},{"actor":"visitor","do":"click","testid":"support-submit"},{"actor":"visitor","do":"expect","nonEmpty":true,"testid":"support-reference"},{"actor":"staff","do":"signIn","exact":true,"name":"staff","password":"stackbench-staff-2026"},{"actor":"staff","do":"click","testid":"staff-link","unlessVisible":"support-assignee"},{"actor":"staff","do":"click","ifAvailable":true,"testid":"support-queue-link","unlessVisible":"support-assignee"}]},"packId":"ecommerce.progression.support-triage","role":"feature","source":"scenarios/progression-support-triage.json"}],"id":"selected-source-113","scenario":{"level":2,"writeUrlPattern":null},"source":"scenarios/progression-support-triage.json"}],"fixture":{"accounts":[{"password":"stackbench-admin-2026","roles":["admin"],"username":"admin"},{"password":"stackbench-staff-2026","roles":["staff"],"username":"staff"}],"empty":["carts","orders","reviews","returns"],"items":[{"category":"Home","name":"Air Purifier","price":"189.00","stock":{"East":60,"West":40}},{"category":"Audio","name":"Bluetooth Speaker","price":"79.50","stock":{"East":50,"West":50}},{"category":"Home","name":"Coffee Grinder","price":"64.00","stock":{"East":70,"West":30}},{"category":"Home","name":"Desk Lamp","price":"42.00","stock":{"East":55,"West":45}},{"category":"Home","name":"Espresso Machine","price":"449.00","stock":{"East":80,"West":20}},{"category":"Computing","name":"Gaming Mouse","price":"59.00","stock":{"East":50,"West":50}},{"category":"Audio","name":"Headphones","price":"199.00","stock":{"East":60,"West":40}},{"category":"Home","name":"Induction Cooktop","price":"329.00","stock":{"East":50,"West":50}},{"category":"Computing","name":"Keyboard","price":"89.00","stock":{"East":70,"West":30}},{"category":"Computing","name":"Laptop Stand","price":"29.00","stock":{"East":90,"West":10}},{"category":"Photo","name":"Mirrorless Camera","price":"1299.00","stock":{"East":2,"West":1}},{"category":"Home","name":"USB Cable","price":"65.00","stock":{"East":0,"West":0}},{"category":"Computing","name":"Webcam","price":"69.00","stock":{"East":60,"West":40}}],"warehouses":["East","West"]},"packs":[{"actions":["click","expect","signIn","signUp","waitUntilAbsent"],"budget":{"maxRuntimeMs":18000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.feature.accounts","includeRoles":["feature"],"moduleType":"feature"},{"actions":["click","dbExpectStock","dbSetStock","expect","expectNumber","fill","signIn","signUp"],"budget":{"maxRuntimeMs":120000,"status":"bounded"},"capabilities":["browser","database-observation","direct-database-write"],"evidence":["browser-observation","database-observation"],"id":"ecommerce.feature.bundle-checkout","includeRoles":["feature"],"moduleType":"feature"},{"actions":["click","dbExpectStock","dbSetStock","expect","expectNumber","fill","signIn","signUp"],"budget":{"maxRuntimeMs":120000,"status":"bounded"},"capabilities":["browser","database-observation","direct-database-write"],"evidence":["browser-observation","database-observation"],"id":"ecommerce.feature.bundle-returns","includeRoles":["feature"],"moduleType":"feature"},{"actions":["click","expect","expectNumber","signUp","wait"],"budget":{"maxRuntimeMs":42000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.feature.cart","includeRoles":["feature"],"moduleType":"feature","stableId":"ecommerce.feature.cart-checkout"},{"actions":["expect","expectSequence","fill"],"budget":{"maxRuntimeMs":30000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.feature.catalog-discovery","includeRoles":["feature"],"moduleType":"feature","stableId":"ecommerce.feature.catalog"},{"actions":["expect","expectNumber"],"budget":{"maxRuntimeMs":30000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.feature.catalog-items","includeRoles":["feature"],"moduleType":"feature","stableId":"ecommerce.feature.catalog"},{"actions":["click","ensureSignedIn","expect","expectNumber","reload","signUp","wait"],"budget":{"maxRuntimeMs":42000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.feature.checkout","includeRoles":["feature"],"moduleType":"feature","stableId":"ecommerce.feature.cart-checkout"},{"actions":["click","expect","expectElementCount","expectNumber","fill","reload","signIn"],"budget":{"maxRuntimeMs":120000,"status":"bounded"},"capabilities":["browser","database-observation","direct-database-write"],"evidence":["browser-observation","database-observation"],"id":"ecommerce.feature.product-bundles","includeRoles":["feature"],"moduleType":"feature"},{"actions":["click","expect","expectNumber","signUp"],"budget":{"maxRuntimeMs":24000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.feature.purchasing","includeRoles":["feature"],"moduleType":"feature"},{"actions":["click","expect","fill","openItem","signUp"],"budget":{"maxRuntimeMs":22000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.feature.reviews","includeRoles":["feature"],"moduleType":"feature"},{"actions":["callAction","click","dbExpectStock","dbRecordStock","ensureSignedIn","expect","expectActionOutcome","expectElementCount","expectNumber","fill","freshClient","recordNumber","reload","signIn","signUp"],"budget":{"maxRuntimeMs":120000,"status":"bounded"},"capabilities":["browser","database-observation","direct-server-call"],"evidence":["browser-observation","database-observation","fresh-client-observation"],"id":"ecommerce.feature.split-tender-refunds","includeRoles":["feature"],"moduleType":"feature"},{"actions":["callAction","click","ensureSignedIn","expect","expectActionOutcome","expectElementCount","expectNumber","fill","freshClient","reload","signIn","signUp"],"budget":{"maxRuntimeMs":180000,"status":"bounded"},"capabilities":["browser","direct-server-call"],"evidence":["browser-observation","fresh-client-observation"],"id":"ecommerce.feature.store-credit","includeRoles":["feature"],"moduleType":"feature"},{"actions":["click","dbExpectStock","dbSetStock","expect","expectElementCount","expectNumber","expectSequence","fill","freshClient","signIn","signUp"],"budget":{"maxRuntimeMs":180000,"status":"bounded"},"capabilities":["browser","database-observation","direct-server-call"],"evidence":["browser-observation","database-observation","fresh-client-observation"],"id":"ecommerce.feature.subscriptions","includeRoles":["feature"],"moduleType":"feature"},{"actions":["callAction","click","ensureSignedIn","expect","expectActionOutcome","expectNumber","recordNumber","reload","signIn"],"budget":{"maxRuntimeMs":30000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.feature.warehouse-admin","includeRoles":["feature"],"moduleType":"feature"},{"actions":["click","dbSetStock","ensureSignedIn","expect","reload","signIn","signUp"],"budget":{"maxRuntimeMs":86000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.l2.inventory-dashboard","includeRoles":["feature"],"moduleType":"feature","stableId":"ecommerce.inventory-operations"},{"actions":["click","ensureSignedIn","expect","expectNumber","recordNumber","reload","signIn","signUp"],"budget":{"maxRuntimeMs":60000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.l2.order-cancellation-features","includeRoles":["feature"],"moduleType":"feature","stableId":"ecommerce.returns-pricing"},{"actions":["click","expectNumber","fill","signIn"],"budget":{"maxRuntimeMs":94000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.l2.price-history-features","includeRoles":["feature"],"moduleType":"feature","stableId":"ecommerce.returns-pricing"},{"actions":["click","expect","signUp","waitUntilAbsent"],"budget":{"maxRuntimeMs":86000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.l2.recommendations","includeRoles":["feature"],"moduleType":"feature","stableId":"ecommerce.inventory-operations"},{"actions":["click","ensureSignedIn","expect","expectNumber","recordNumber","reload","signIn","signUp"],"budget":{"maxRuntimeMs":86000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.l2.sales-dashboard","includeRoles":["feature"],"moduleType":"feature","stableId":"ecommerce.inventory-operations"},{"actions":["click","dbExpectStock","dbRecordStock","expect","expectNumber","fill","recordNumber","signIn"],"budget":{"maxRuntimeMs":86000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.l2.stock-transfers-features","includeRoles":["feature"],"moduleType":"feature","stableId":"ecommerce.inventory-operations"},{"actions":["click","closeClient","expect","expectNumber","openClient","recordNumber","reload","signUp","wait"],"budget":{"maxRuntimeMs":360000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.l3.cart-expiration-features","includeRoles":["feature"],"moduleType":"feature","stableId":"ecommerce.l3.cart-expiration"},{"actions":["callAction","click","expect","expectActionOutcome","expectReplayRejected","fill","replayAs","signIn","signUp"],"budget":{"maxRuntimeMs":60000,"status":"bounded"},"capabilities":["browser","direct-server-call","request-replay"],"evidence":["browser-observation","server-refusal","server-response"],"id":"ecommerce.l3.deferred-access-specifications","includeRoles":["guarantee"],"moduleType":"specification","stableId":"ecommerce.l3.deferred-access"},{"actions":["click","dbExpectStock","dbRecordStock","ensureSignedIn","expect","expectElapsed","expectNumber","fill","recordNumber","recordTime","reload","restartBackend","signIn","signUp","wait"],"budget":{"maxRuntimeMs":720000,"status":"bounded"},"capabilities":["backend-lifecycle","browser"],"evidence":["browser-observation","database-observation"],"id":"ecommerce.l3.deferred-durability-specifications","includeRoles":["guarantee"],"moduleType":"specification","stableId":"ecommerce.l3.deferred-durability"},{"actions":["click","dbExpectStock","dbRecordStock","ensureSignedIn","expect","expectElementCount","expectNumber","fill","recordNumber","reload","restartBackend","signIn","signUp","wait"],"budget":{"maxRuntimeMs":400000,"status":"bounded"},"capabilities":["backend-lifecycle","browser"],"evidence":["browser-observation","database-observation"],"id":"ecommerce.l3.deferred-integrity-specifications","includeRoles":["guarantee"],"moduleType":"specification","stableId":"ecommerce.l3.deferred-integrity"},{"actions":["click","ensureSignedIn","expect","reload","signIn","signUp","wait"],"budget":{"maxRuntimeMs":190000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.l3.order-delivery-features","includeRoles":["feature"],"moduleType":"feature","stableId":"ecommerce.l3.order-delivery"},{"actions":["callAction","click","dbExpectStock","dbRecordStock","ensureSignedIn","expect","expectActionOutcome","expectNumber","freshClient","recordNumber","reload","signIn","signUp"],"budget":{"maxRuntimeMs":120000,"status":"bounded"},"capabilities":["browser","database-observation"],"evidence":["browser-observation","database-observation","fresh-client-observation"],"id":"ecommerce.l3.order-returns-features","includeRoles":["feature"],"moduleType":"feature","stableId":"ecommerce.returns-pricing"},{"actions":["click","expect","expectNumber","recordNumber","signUp","wait"],"budget":{"maxRuntimeMs":300000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.l3.reservations-features","includeRoles":["feature"],"moduleType":"feature","stableId":"ecommerce.l3.reservations"},{"actions":["click","ensureSignedIn","expect","expectElementCount","expectNumber","fill","recordNumber","reload","signIn","wait"],"budget":{"maxRuntimeMs":150000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.l3.scheduled-restocks-features","includeRoles":["feature"],"moduleType":"feature","stableId":"ecommerce.l3.scheduled-restocks"},{"actions":["click","closeClient","dbExpectStock","dbRecordStock","ensureSignedIn","expect","expectElapsed","expectNumber","fill","recordNumber","recordTime","reload","restartBackend","signIn","signUp","wait"],"budget":{"maxRuntimeMs":300000,"status":"bounded"},"capabilities":["backend-lifecycle","browser"],"evidence":["browser-observation","database-observation"],"id":"ecommerce.l3.server-time-specifications","includeRoles":["guarantee"],"moduleType":"specification","stableId":"ecommerce.l3.server-time"},{"actions":["callAction","click","dbExpectStock","dbSetStock","ensureSignedIn","expect","expectActionOutcome","expectElementCount","fill","reload","signIn","signUp"],"budget":{"maxRuntimeMs":90000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.progression.automatic-reorder","includeRoles":["feature"],"moduleType":"feature"},{"actions":["callConcurrently","click","dbExpectCancellation","dbRecordCheckout","ensureSignedIn","expect","expectCallOutcomes","expectNumber","recordNumber","reload","signIn","signUp","wait"],"budget":{"maxRuntimeMs":24000,"status":"bounded"},"capabilities":["browser","concurrent-actors","direct-server-call"],"evidence":["browser-observation","concurrent-outcome","database-observation"],"id":"ecommerce.progression.cancellation-accounting-specifications","includeRoles":["guarantee"],"moduleType":"specification","stableId":"ecommerce.returns-pricing"},{"actions":["click","expect","signIn","signUp","waitUntilAbsent"],"budget":{"maxRuntimeMs":24000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.progression.cancellation-queue-specifications","includeRoles":["guarantee"],"moduleType":"specification","stableId":"ecommerce.returns-pricing"},{"actions":["click","dbSetStock","ensureSignedIn","expect","expectNumber","recordNumber","reload","signUp","wait"],"budget":{"maxRuntimeMs":350000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.progression.cart-recovery","includeRoles":["feature"],"moduleType":"feature"},{"actions":["click","expect","expectElementCount","fill","openItem","reload","signIn"],"budget":{"maxRuntimeMs":30000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.progression.catalog-management","includeRoles":["feature"],"moduleType":"feature"},{"actions":["click","expect","fill","signUp"],"budget":{"maxRuntimeMs":30000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.progression.customer-profile","includeRoles":["feature"],"moduleType":"feature"},{"actions":["callAction","click","ensureSignedIn","expect","expectActionOutcome","expectElapsed","expectElementCount","recordTime","reload","signIn","signUp","wait"],"budget":{"maxRuntimeMs":110000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.progression.delivery-notifications","includeRoles":["feature"],"moduleType":"feature"},{"actions":["click","dbSetStock","expect","expectElementCount","expectSequence","fill","reload","waitUntilAbsent"],"budget":{"maxRuntimeMs":141000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.progression.faceted-search","includeRoles":["feature"],"moduleType":"feature"},{"actions":["callAction","click","dbSetStock","ensureSignedIn","expect","expectActionOutcome","reload","signIn","signUp"],"budget":{"maxRuntimeMs":76000,"status":"bounded"},"capabilities":["browser","direct-server-call"],"evidence":["browser-observation","server-refusal"],"id":"ecommerce.progression.fulfilment-queue","includeRoles":["feature"],"moduleType":"feature","stableId":"ecommerce.operations-access"},{"actions":["callAction","click","dbExpectStock","dbRecordStock","ensureSignedIn","expect","expectActionOutcome","expectNumber","fill","freshClient","race","recordNumber","reload","signIn","signUp"],"budget":{"maxRuntimeMs":138000,"status":"bounded"},"capabilities":["browser","concurrent-actors","direct-server-call"],"evidence":["browser-observation","server-response"],"id":"ecommerce.progression.inventory-conservation-specifications","includeRoles":["guarantee"],"moduleType":"specification","stableId":"ecommerce.inventory-operations"},{"actions":["click","ensureSignedIn","expect","fill","reload","signIn","signUp"],"budget":{"maxRuntimeMs":55000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.progression.managed-support","includeRoles":["feature"],"moduleType":"feature"},{"actions":["click","expect","signUp"],"budget":{"maxRuntimeMs":40000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.progression.notification-preferences","includeRoles":["feature"],"moduleType":"feature"},{"actions":["callAction","click","dbExpectStock","dbRecordStock","ensureSignedIn","expect","expectActionOutcome","expectNumber","fill","recordNumber","reload","signIn","signUp"],"budget":{"maxRuntimeMs":98000,"status":"bounded"},"capabilities":["browser","direct-server-call","request-replay"],"evidence":["server-refusal","server-response"],"id":"ecommerce.progression.operations-access-specifications","includeRoles":["guarantee"],"moduleType":"specification","stableId":"ecommerce.operations-access"},{"actions":["click","expect","fill","signIn","signUp"],"budget":{"maxRuntimeMs":65000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.progression.order-support","includeRoles":["feature"],"moduleType":"feature"},{"actions":["callConcurrently","click","expect","expectCallOutcomes","expectElementCount","expectNumber","freshClient","recordNumber","signIn","signUp"],"budget":{"maxRuntimeMs":30000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.progression.payment-records","includeRoles":["feature"],"moduleType":"feature"},{"actions":["click","expect","expectNumber","expectSequence","signUp"],"budget":{"maxRuntimeMs":70000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.progression.personalized-recommendations","includeRoles":["feature"],"moduleType":"feature"},{"actions":["click","ensureSignedIn","expect","expectNumber","fill","pressKey","recordNumber","reload","signIn","signUp","wait"],"budget":{"maxRuntimeMs":24000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.progression.price-accounting-specifications","includeRoles":["guarantee"],"moduleType":"specification","stableId":"ecommerce.returns-pricing"},{"actions":["callAction","click","ensureSignedIn","expect","expectActionOutcome","expectNumber","fill","freshClient","recordNumber","reload","signIn","signUp"],"budget":{"maxRuntimeMs":94000,"status":"bounded"},"capabilities":["browser","direct-server-call"],"evidence":["browser-observation","fresh-client-observation"],"id":"ecommerce.progression.price-history-specifications","includeRoles":["guarantee"],"moduleType":"specification","stableId":"ecommerce.returns-pricing"},{"actions":["click","expect","expectNumber","fill","signIn","signUp"],"budget":{"maxRuntimeMs":55000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.progression.promotion-checkout","includeRoles":["feature"],"moduleType":"feature"},{"actions":["click","expectNumber","fill","signIn","signUp"],"budget":{"maxRuntimeMs":40000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.progression.promotion-reporting","includeRoles":["feature"],"moduleType":"feature"},{"actions":["click","expect","expectNumber","fill","signIn","signUp"],"budget":{"maxRuntimeMs":45000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.progression.promotion-rules","includeRoles":["feature"],"moduleType":"feature"},{"actions":["click","expect","signUp"],"budget":{"maxRuntimeMs":130000,"status":"bounded"},"capabilities":["backend-lifecycle","browser"],"evidence":["browser-observation","fresh-client-observation"],"id":"ecommerce.progression.recommendation-feedback","includeRoles":["feature"],"moduleType":"feature"},{"actions":["armScriptCanary","callAction","click","expect","expectActionOutcome","expectNoScriptExecution","freshClient","openItem","signIn","signUp","wait"],"budget":{"maxRuntimeMs":82000,"status":"bounded"},"capabilities":["browser","direct-server-call","request-replay"],"evidence":["browser-observation","fresh-client-observation","server-refusal","server-response"],"id":"ecommerce.progression.review-access-specifications","includeRoles":["guarantee"],"moduleType":"specification"},{"actions":["click","expect","signIn"],"budget":{"maxRuntimeMs":30000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.progression.staff-access","includeRoles":["feature"],"moduleType":"feature"},{"actions":["click","expect","fill","signIn"],"budget":{"maxRuntimeMs":30000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.progression.staff-activity","includeRoles":["feature"],"moduleType":"feature"},{"actions":["click","expect","fill","signIn"],"budget":{"maxRuntimeMs":30000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.progression.staff-roles","includeRoles":["feature"],"moduleType":"feature"},{"actions":["callAction","click","dbSetStock","ensureSignedIn","expect","expectActionOutcome","expectElementCount","freshClient","reload","signIn","signUp","wait"],"budget":{"maxRuntimeMs":60000,"status":"bounded"},"capabilities":["browser","direct-database-write"],"evidence":["browser-observation"],"id":"ecommerce.progression.stock-alerts","includeRoles":["feature"],"moduleType":"feature"},{"actions":["click","ensureSignedIn","expect","fill","reload","signUp"],"budget":{"maxRuntimeMs":50000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.progression.support-history","includeRoles":["feature"],"moduleType":"feature"},{"actions":["click","expect","fill"],"budget":{"maxRuntimeMs":30000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.progression.support-intake","includeRoles":["feature"],"moduleType":"feature"},{"actions":["click","expect","fill","signIn","signUp"],"budget":{"maxRuntimeMs":70000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.progression.support-refunds","includeRoles":["feature"],"moduleType":"feature"},{"actions":["click","ensureSignedIn","expect","fill","reload","signIn"],"budget":{"maxRuntimeMs":45000,"status":"bounded"},"capabilities":["browser"],"evidence":["browser-observation"],"id":"ecommerce.progression.support-triage","includeRoles":["feature"],"moduleType":"feature"},{"actions":["callAction","click","dbExpectStock","dbRecordStock","dbSetStock","ensureSignedIn","expect","expectActionOutcome","expectElapsed","expectElementCount","expectNotReceived","expectNumber","expectReceived","expectReplayCompleted","expectReplayRejected","expectSequence","fill","freshClient","openItem","recordNumber","recordTime","reload","replayAs","signIn","signUp","wait","waitUntilAbsent"],"budget":{"maxRuntimeMs":464000,"status":"bounded"},"capabilities":["backend-lifecycle","browser","direct-server-call","request-replay"],"evidence":["browser-observation","database-observation","fresh-client-observation","server-response"],"id":"ecommerce.spec.access-control","includeRoles":["guarantee"],"moduleType":"specification"},{"actions":["callAction","callConcurrently","click","dbExpectStock","dbSetStock","ensureSignedIn","expect","expectActionOutcome","expectActorsWith","expectCallOutcomes","expectNumber","fill","reload","restartBackend","signIn","signUp","wait"],"budget":{"maxRuntimeMs":480000,"status":"bounded"},"capabilities":["backend-lifecycle","browser","database-observation","direct-database-write","direct-server-call"],"evidence":["browser-observation","database-observation","fresh-client-observation"],"id":"ecommerce.spec.bundle-integrity","includeRoles":["guarantee"],"moduleType":"specification"},{"actions":["callAction","callConcurrently","click","clickConcurrently","dbExpectCheckout","dbExpectPurchases","dbExpectStock","dbRecordCheckout","dbRecordStock","dbSetStock","ensureSignedIn","expect","expectActionOutcome","expectActorsWith","expectAgreement","expectCallOutcomes","expectNumber","fill","race","recordNumber","reload","signIn","signUp","wait"],"budget":{"maxRuntimeMs":125000,"status":"bounded"},"capabilities":["browser","concurrent-actors","direct-server-call"],"evidence":["concurrent-outcome","database-observation"],"id":"ecommerce.spec.concurrency-safety","includeRoles":["guarantee"],"moduleType":"specification"},{"actions":["dbSetStock","expectNumber","reload","setOffline","startAppServer","stopAppServer"],"budget":{"maxRuntimeMs":105000,"status":"bounded"},"capabilities":["backend-lifecycle","browser","direct-database-write"],"evidence":["database-observation","fresh-client-observation"],"id":"ecommerce.spec.external-data-sync","includeRoles":["guarantee"],"moduleType":"specification"},{"actions":["callAction","click","dbExpectStock","dbRecordStock","dbSetStock","ensureSignedIn","expect","expectActionOutcome","expectAgreement","expectElementCount","expectNumber","expectSequence","fill","openItem","recordNumber","reload","signIn","signUp","waitUntilAbsent"],"budget":{"maxRuntimeMs":184000,"status":"bounded"},"capabilities":["browser","concurrent-actors"],"evidence":["browser-observation","fresh-client-observation"],"id":"ecommerce.spec.live-state","includeRoles":["guarantee"],"moduleType":"specification"},{"actions":["click","dbExpectStock","dbRecordStock","expectSequence","fill","reload","signUp"],"budget":{"maxRuntimeMs":60000,"status":"bounded"},"capabilities":["browser","database-observation"],"evidence":["browser-observation","database-observation"],"id":"ecommerce.spec.search-ordering","includeRoles":["guarantee"],"moduleType":"specification"},{"actions":["callAction","callConcurrently","click","ensureSignedIn","expect","expectActionOutcome","expectCallOutcomes","expectElementCount","expectNumber","fill","freshClient","reload","restartBackend","signIn","signUp"],"budget":{"maxRuntimeMs":300000,"status":"bounded"},"capabilities":["backend-lifecycle","browser","database-observation","direct-server-call"],"evidence":["browser-observation","database-observation","fresh-client-observation"],"id":"ecommerce.spec.split-tender-refunds","includeRoles":["guarantee"],"moduleType":"specification"},{"actions":["click","confirmCheckout","crashCheckout","dbExpectCheckout","dbRecordCheckout","ensureSignedIn","expect","expectCrashCheckout","expectNumber","fill","freshClient","reload","restartBackend","setOffline","signIn","signUp"],"budget":{"maxRuntimeMs":768000,"status":"bounded"},"capabilities":["backend-lifecycle","browser","database-read","process-crash"],"evidence":["browser-observation","fresh-client-observation"],"id":"ecommerce.spec.state-durability","includeRoles":["guarantee"],"moduleType":"specification"},{"actions":["callAction","callConcurrently","click","ensureSignedIn","expect","expectActionOutcome","expectCallOutcomes","expectElementCount","expectNumber","fill","freshClient","reload","restartBackend","signIn","signUp"],"budget":{"maxRuntimeMs":300000,"status":"bounded"},"capabilities":["backend-lifecycle","browser","database-observation","direct-server-call"],"evidence":["browser-observation","database-observation","fresh-client-observation"],"id":"ecommerce.spec.store-credit","includeRoles":["guarantee"],"moduleType":"specification"},{"actions":["callAction","click","dbExpectStock","dbRecordStock","dbSetStock","expect","expectActionOutcome","expectElementCount","expectNumber","expectSequence","fill","freshClient","recordNumber","restartBackend","signIn","signUp","wait"],"budget":{"maxRuntimeMs":480000,"status":"bounded"},"capabilities":["backend-lifecycle","browser","database-observation","direct-server-call"],"evidence":["browser-observation","database-observation","fresh-client-observation"],"id":"ecommerce.spec.subscriptions","includeRoles":["guarantee"],"moduleType":"specification"},{"actions":["callAction","callConcurrently","click","dbExpectStock","dbRecordStock","dbSetStock","ensureSignedIn","expect","expectActionOutcome","expectCallOutcomes","expectElementCount","expectNumber","expectReplayCompleted","fill","freshClient","openItem","recordNumber","reload","replayAs","signIn","signUp","wait"],"budget":{"maxRuntimeMs":100000,"status":"bounded"},"capabilities":["browser","database-observation","direct-server-call"],"evidence":["browser-observation","database-observation","server-response"],"id":"ecommerce.spec.transactional-integrity","includeRoles":["guarantee"],"moduleType":"specification"}],"runtime":{"actions":[{"args":[0,1],"id":"addToCart","path":"/api/cart","reducer":"add_to_cart"},{"args":[0],"id":"buy","path":"/api/items/00000000-0000-0000-0000-000000000000/buy","reducer":"buy_now"},{"args":[],"id":"checkout","path":"/api/checkout","reducer":"checkout"},{"args":[0,0,1],"id":"restock","path":"/api/admin/restock","reducer":"admin_restock"},{"args":["",""],"id":"signIn","path":"/api/auth/signin","reducer":"sign_in"},{"args":["",""],"id":"signUp","params":[{"in":"body","name":"username"},{"in":"body","name":"password"}],"path":"/api/auth/signup","reducer":"sign_up"}],"portOffset":300,"reseedOnReset":true,"restartProbe":"/api/items"},"schemaVersion":3,"task":{"baseExecutionSha256":null,"mode":"action"},"track":"ecommerce"}},"calibration":{"calibrationSchemaVersion":2,"controls":[],"equivalenceDecisions":[],"fixture":{"id":"ecommerce.operations","sourceSha256":"d06444b72dc94fe1ef5e08867d875e1f3bbaa5cd82c35a3558f399c1fcb5ceae"},"id":"ecommerce.dependency-l3-calibration","mutations":[{"backend":"mongodb","path":"grader/mutations/mongodb-ecommerce.json","sha256":"90ae4b351ef5e7b06435c1c99f8df96fb850ccad338eeba4e68910560845d875","referenceId":"ecommerce-reference-mongodb","executionSha256":"927e83bd722707a09c763de85f46c8c4bc58e5ce370490a8ddbaaabde6bbcbf7","targets":[{"id":"staff-admin-access-survives-role-removal","stableKeys":["ecommerce.spec.access-control.staff-role-revocation.621d"]},{"id":"shipping-counts-sale-twice","stableKeys":["ecommerce.inventory-operations.shipping-accounting.202e"]},{"id":"signup-does-not-expose-created-account","stableKeys":["ecommerce.feature.accounts.accounts.1a"]},{"id":"duplicate-signup-reports-success","stableKeys":["ecommerce.feature.accounts.accounts.1b"]},{"id":"signin-skips-password-verification","stableKeys":["ecommerce.feature.accounts.accounts.1c"]},{"id":"signout-keeps-current-account","stableKeys":["ecommerce.feature.accounts.accounts.1d"]},{"id":"session-token-not-persisted","stableKeys":["ecommerce.spec.state-durability.session-reload.1e"]},{"id":"purchase-counts-never-affect-ranking","stableKeys":["ecommerce.spec.live-state.ranking.2c"]},{"id":"signed-out-visitor-purchase-is-accepted","stableKeys":["ecommerce.spec.access-control.signed-out-purchase.3a"]},{"id":"espresso-stock-row-ignores-live-updates","stableKeys":["ecommerce.spec.live-state.purchase-stock.3b"]},{"id":"restock-race-records-wrong-order-total","stableKeys":["ecommerce.spec.concurrency-safety.restock-race.202a"]},{"id":"purchase-order-uses-zero-price","stableKeys":["ecommerce.feature.purchasing.purchase-order.3c"]},{"id":"reload-hydrates-an-empty-cart","stableKeys":["ecommerce.spec.state-durability.cart-reload.4b"]},{"id":"shared-cart-live-events-ignored","stableKeys":["ecommerce.spec.live-state.shared-cart.4c"]},{"id":"review-comment-is-not-persisted","stableKeys":["ecommerce.feature.reviews.reviews.6a"]},{"id":"repeat-review-uses-a-new-owner-key","stableKeys":["ecommerce.spec.transactional-integrity.unique-review.6b"]},{"id":"live-review-average-uses-an-extra-divisor","stableKeys":["ecommerce.spec.live-state.rating.6c"]},{"id":"warehouse-view-omits-one-location","stableKeys":["ecommerce.feature.warehouse-admin.warehouse-view.7b"]},{"id":"unauthenticated-purchase-defaults-to-admin","stableKeys":["ecommerce.spec.access-control.purchase-session.101a"]},{"id":"direct-purchase-total-ignores-store-price","stableKeys":["ecommerce.spec.transactional-integrity.server-price.104a"]},{"id":"cart-hydration-loses-account-state","stableKeys":["ecommerce.spec.state-durability.account-state-recovery.105a"]},{"id":"reconnect-hydration-loses-account-state","stableKeys":["ecommerce.spec.state-durability.account-state-recovery.105b"]},{"id":"order-history-is-not-owner-scoped","stableKeys":["ecommerce.spec.access-control.order-ownership.106a"]},{"id":"revenue-aggregation-ignores-order-totals","stableKeys":["ecommerce.spec.transactional-integrity.books-balance.107a"]},{"id":"unpurchased-review-is-accepted","stableKeys":["ecommerce.spec.access-control.review-eligibility.108a"]},{"id":"purchased-review-ui-does-not-submit","stableKeys":["ecommerce.spec.access-control.review-eligibility.108b"]},{"id":"external-stock-polling-disabled","stableKeys":["ecommerce.spec.external-data-sync.external-stock.901a"]},{"id":"server-restart-disables-catalog-recovery","stableKeys":["ecommerce.spec.external-data-sync.external-stock.901c"]},{"id":"reconnect-generation-ignores-current-catalog","stableKeys":["ecommerce.spec.external-data-sync.external-stock.901d"]},{"id":"open-review-list-ignores-live-update","stableKeys":["ecommerce.spec.live-state.open-list.902a"]},{"id":"cancel-does-not-restore-stock-feature","stableKeys":["ecommerce.returns-pricing.cancellation-and-return.3a"]},{"id":"cancellation-accounting-loses-stock-restoration","stableKeys":["ecommerce.returns-pricing.refund-accounting.203a"]},{"id":"cancel-does-not-restore-stock-fresh-client","stableKeys":["ecommerce.inventory-operations.stock-conservation.202b","ecommerce.inventory-operations.stock-conservation.202c"]},{"id":"cancel-restores-stock-but-keeps-pending-status","stableKeys":["ecommerce.returns-pricing.cancellation-and-return.3b"]},{"id":"cancelled-order-remains-in-revenue-feature","stableKeys":["ecommerce.returns-pricing.cancellation-and-return.3a"]},{"id":"cancelled-order-remains-in-revenue-invariant","stableKeys":["ecommerce.returns-pricing.refund-accounting.203a"]},{"id":"operator-authorization-allows-customer-transfer","stableKeys":["ecommerce.operations-access.operator-authorization.201a"]},{"id":"customer-can-ship-order-direct-1-1","stableKeys":["ecommerce.operations-access.operator-authorization.201c"]},{"id":"customer-can-cancel-foreign-order-1-1","stableKeys":["ecommerce.operations-access.order-owner.204a"]},{"id":"ship-acknowledges-without-changing-status","stableKeys":["ecommerce.operations-access.fulfilment-queue.1c"]},{"id":"progression-customer-sees-fulfilment-content","stableKeys":["ecommerce.spec.access-control.fulfilment-area-boundary.1d"]},{"id":"transfer-debits-source-without-crediting-existing-destination","stableKeys":["ecommerce.inventory-operations.stock-conservation.202a","ecommerce.inventory-operations.warehouse-transfer.2a","ecommerce.operations-access.operator-authorization.201a"]},{"id":"recommendations-ignore-pending-purchases","stableKeys":["ecommerce.inventory-operations.operational-views.5c"]},{"id":"purchases-do-not-affect-best-sellers","stableKeys":["ecommerce.inventory-operations.operational-views.5d"]},{"id":"queue-warehouse-reports-west","stableKeys":["ecommerce.operations-access.fulfilment-queue.1b"]},{"id":"cart-repeat-does-not-increment","stableKeys":["ecommerce.feature.cart-checkout.cart.4a"]},{"id":"checkout-leaves-cart-claimed","stableKeys":["ecommerce.feature.cart-checkout.cart.4d"]},{"id":"catalog-initial-ranking-is-reversed","stableKeys":["ecommerce.feature.catalog.catalog-ranking.2b"]},{"id":"catalog-search-requires-exact-name","stableKeys":["ecommerce.feature.catalog.catalog-search.2d"]},{"id":"catalog-price-is-offset","stableKeys":["ecommerce.feature.catalog.catalog-values.2a"]},{"id":"staff-can-see-admin-navigation","stableKeys":["ecommerce.spec.access-control.warehouse-area-boundary.7a"]},{"id":"staff-can-use-direct-restock","stableKeys":["ecommerce.spec.access-control.warehouse-write-boundary.103b"]},{"id":"restock-adds-the-wrong-quantity","stableKeys":["ecommerce.spec.live-state.warehouse-stock.7c"]},{"id":"transfer-creates-stock-during-race","stableKeys":["ecommerce.inventory-operations.stock-conservation.202d"]},{"id":"customer-can-cancel-scheduled-restock","stableKeys":["ecommerce.l3.deferred-access.scheduled-work-access.317a"]},{"id":"scheduled-restock-never-becomes-due-after-restart","stableKeys":["ecommerce.l3.deferred-durability.restart-survival.311a"]},{"id":"completed-restock-is-replayed","stableKeys":["ecommerce.l3.deferred-integrity.exactly-once.311a"]},{"id":"scheduled-restock-countdown-is-fixed","stableKeys":["ecommerce.l3.scheduled-restocks.scheduled-restocks.302a"]},{"id":"due-restock-does-not-change-stock","stableKeys":["ecommerce.l3.scheduled-restocks.scheduled-restocks.305a"]},{"id":"cancelled-restock-remains-pending","stableKeys":["ecommerce.l3.scheduled-restocks.scheduled-restocks.306a"]},{"id":"server-time-restock-never-completes","stableKeys":["ecommerce.l3.server-time.server-time.312a"]},{"id":"catalog-product-name-is-not-published","stableKeys":["ecommerce.progression.catalog-management.catalog-management.622a","ecommerce.progression.catalog-management.catalog-management.622b"]},{"id":"catalog-variants-are-discarded","stableKeys":["ecommerce.progression.catalog-management.catalog-management.622b"]},{"id":"profile-data-is-lost-on-server-restart","stableKeys":["ecommerce.spec.state-durability.customer-profile-reload.620a"]},{"id":"profile-read-is-not-owner-scoped","stableKeys":["ecommerce.spec.access-control.customer-profile-privacy.620b"]},{"id":"faceted-search-ignores-category","stableKeys":["ecommerce.progression.faceted-search.faceted-search.401a"]},{"id":"active-search-uses-purchase-ranking","stableKeys":["ecommerce.spec.search-ordering.search-ordering.402b"]},{"id":"pagination-repeats-first-page","stableKeys":["ecommerce.progression.faceted-search.faceted-search.402a"]},{"id":"managed-support-live-refresh-keeps-stale-tickets","stableKeys":["ecommerce.spec.live-state.managed-support.613a"]},{"id":"managed-support-allows-another-customer","stableKeys":["ecommerce.spec.access-control.managed-support-privacy.613b"]},{"id":"notification-preference-is-not-saved","stableKeys":["ecommerce.spec.state-durability.notification-preferences-reload.630a","ecommerce.progression.notification-preferences.notification-preferences.630c"]},{"id":"notification-preference-is-not-owner-scoped","stableKeys":["ecommerce.spec.access-control.notification-preferences-privacy.630b"]},{"id":"promotion-save-drops-bounded-values","stableKeys":["ecommerce.progression.promotion-rules.promotion-rule-values.620a"]},{"id":"customer-can-create-promotion","stableKeys":["ecommerce.spec.access-control.promotion-management-boundary.620b"]},{"id":"staff-signin-loses-staff-role","stableKeys":["ecommerce.progression.staff-access.staff-access.601a"]},{"id":"customer-signin-gains-staff-role","stableKeys":["ecommerce.spec.access-control.staff-area-boundary.601b"]},{"id":"role-assignment-drops-role","stableKeys":["ecommerce.spec.state-durability.staff-role-reload.621a"]},{"id":"staff-role-write-precedes-denial","stableKeys":["ecommerce.spec.access-control.staff-role-boundary.621b","ecommerce.spec.access-control.staff-role-revocation.621d"]},{"id":"staff-can-assign-roles","stableKeys":["ecommerce.spec.access-control.staff-role-boundary.621b","ecommerce.spec.access-control.staff-role-revocation.621d"]},{"id":"stock-alert-delivery-is-suppressed","stableKeys":["ecommerce.progression.stock-alerts.stock-alert-delivery.631c"]},{"id":"stock-alert-repeats-while-in-stock","stableKeys":["ecommerce.spec.transactional-integrity.stock-alert-deduplication.631a"]},{"id":"stock-alerts-are-not-owner-scoped","stableKeys":["ecommerce.spec.access-control.stock-alert-privacy.631b"]},{"id":"support-history-is-lost-on-server-restart","stableKeys":["ecommerce.spec.state-durability.support-history-reload.612a"]},{"id":"support-history-is-not-owner-scoped","stableKeys":["ecommerce.spec.access-control.support-history-privacy.612b"]},{"id":"support-intake-returns-no-reference","stableKeys":["ecommerce.progression.support-intake.support-intake.610a"]},{"id":"support-triage-discards-updates","stableKeys":["ecommerce.progression.support-triage.support-assignment.611a","ecommerce.progression.support-triage.support-priority.611b","ecommerce.progression.support-triage.support-status.611c"]},{"id":"cart-add-uses-another-account-cart","stableKeys":["ecommerce.spec.access-control.cart-boundary.109a"]},{"id":"negative-cart-quantity-is-accepted","stableKeys":["ecommerce.spec.access-control.cart-boundary.109b"]},{"id":"direct-purchase-is-attributed-to-another-account","stableKeys":["ecommerce.spec.access-control.purchase-attribution.102a"]},{"id":"concurrent-cart-add-does-not-increment","stableKeys":["ecommerce.spec.concurrency-safety.duplicate-checkout.203a"]},{"id":"checkout-claim-is-not-atomic","stableKeys":["ecommerce.spec.concurrency-safety.duplicate-checkout.203b"]},{"id":"last-unit-allows-negative-stock","stableKeys":["ecommerce.spec.concurrency-safety.last-unit.201a","ecommerce.spec.concurrency-safety.last-unit.201b","ecommerce.spec.concurrency-safety.last-unit.201c"]},{"id":"purchase-read-write-loses-concurrent-stock","stableKeys":["ecommerce.spec.concurrency-safety.restock-race.202a"]},{"id":"purchase-does-not-reduce-warehouse-stock","stableKeys":["ecommerce.spec.transactional-integrity.books-balance.107b"]},{"id":"restock-does-not-increase-stock","stableKeys":["ecommerce.spec.live-state.warehouse-stock.7c"]},{"id":"direct-review-access-is-not-checked","stableKeys":["ecommerce.progression.review-access-specifications.review-eligibility-direct.618a"]},{"id":"support-history-rows-are-hidden","stableKeys":["ecommerce.progression.support-history.support-history.612c","ecommerce.spec.state-durability.support-history-reload.612a","ecommerce.spec.access-control.support-history-privacy.612b","ecommerce.spec.access-control.support-history-logout.612d"]},{"id":"authorized-restock-does-not-change-stock","stableKeys":["ecommerce.feature.warehouse-admin.admin-write.103a"]},{"id":"initial-dashboard-load-omits-low-stock","stableKeys":["ecommerce.inventory-operations.operational-views.5e","ecommerce.spec.live-state.inventory-dashboard.5a"]},{"id":"category-totals-skip-the-newest-order","stableKeys":["ecommerce.inventory-operations.operational-views.5f"]},{"id":"profile-summary-frozen-at-open","stableKeys":["ecommerce.progression.customer-profile.customer-profile.620c"]},{"id":"support-replies-present-at-open-are-hidden","stableKeys":["ecommerce.progression.managed-support.managed-support.613c"]},{"id":"notification-toggle-frozen-at-open","stableKeys":["ecommerce.progression.notification-preferences.notification-preferences.630c"]},{"id":"role-editor-snaps-back-to-stored-role","stableKeys":["ecommerce.progression.staff-roles.staff-roles.621c"]},{"id":"queue-ignores-live-fulfilment-updates","stableKeys":["ecommerce.spec.live-state.fulfilment-queue.1a"]},{"id":"low-stock-boundary-excludes-ten-live","stableKeys":["ecommerce.spec.live-state.inventory-dashboard.5a"]},{"id":"live-admin-updates-keep-stale-category-totals","stableKeys":["ecommerce.spec.live-state.sales-dashboard.5b"]},{"id":"overdraw-transfer-is-accepted","stableKeys":["ecommerce.spec.transactional-integrity.stock-transfer-overdraw.2c"]},{"id":"transfer-totals-omit-destination-credit-live","stableKeys":["ecommerce.spec.live-state.stock-transfers.2b"]},{"id":"support-history-leaks-to-signed-out-visitors","stableKeys":["ecommerce.spec.access-control.support-history-logout.612d"]},{"id":"checkout-crash-integrity","stableKeys":["ecommerce.spec.state-durability.checkout-crash-integrity.910a"]},{"id":"checkout-crash-durability","stableKeys":["ecommerce.spec.state-durability.checkout-crash-durability.910b"]},{"id":"review-script-unsafe-render","stableKeys":["ecommerce.progression.review-access-specifications.stored-review-script.9180a"]},{"id":"review-script-reject-all","stableKeys":["ecommerce.progression.review-access-specifications.stored-review-script.9180a"]}]},{"backend":"postgres","path":"grader/mutations/postgres-ecommerce.json","sha256":"ead84228c726f2b69d80de5c7bad2e96757a16b9540874fd291de8ddb7542c75","referenceId":"ecommerce-reference-postgres","executionSha256":"194ecf8d31ee18c1e78b15e84a6ae92d4fd32f0b759f12755ba0ffab42978562","targets":[{"id":"staff-admin-access-survives-role-removal","stableKeys":["ecommerce.spec.access-control.staff-role-revocation.621d"]},{"id":"shipping-counts-sale-twice","stableKeys":["ecommerce.inventory-operations.shipping-accounting.202e"]},{"id":"signup-ui-does-not-enter-created-account","stableKeys":["ecommerce.feature.accounts.accounts.1a"]},{"id":"duplicate-signup-authenticates-existing-account","stableKeys":["ecommerce.feature.accounts.accounts.1b"]},{"id":"password-verification-is-inverted","stableKeys":["ecommerce.feature.accounts.accounts.1c"]},{"id":"correct-signin-is-refused","stableKeys":["ecommerce.feature.accounts.accounts.1d"]},{"id":"reload-discards-session-identity","stableKeys":["ecommerce.spec.state-durability.session-reload.1e"]},{"id":"purchase-does-not-broadcast-ranking","stableKeys":["ecommerce.spec.live-state.ranking.2c"]},{"id":"signed-out-purchase-uses-default-account","stableKeys":["ecommerce.spec.access-control.signed-out-purchase.3a"]},{"id":"purchase-stock-change-is-not-broadcast--01-buying","stableKeys":["ecommerce.spec.live-state.purchase-stock.3b"]},{"id":"restock-race-records-wrong-order-total","stableKeys":["ecommerce.spec.concurrency-safety.restock-race.202a"]},{"id":"direct-purchase-order-total-is-offset","stableKeys":["ecommerce.feature.purchasing.purchase-order.3c"]},{"id":"reload-hydrates-an-empty-cart","stableKeys":["ecommerce.spec.state-durability.cart-reload.4b"]},{"id":"signed-out-visitors-do-not-see-reviews","stableKeys":["ecommerce.feature.reviews.reviews.6a"]},{"id":"review-average-update-is-not-broadcast","stableKeys":["ecommerce.spec.live-state.rating.6c"]},{"id":"admin-warehouse-view-drops-one-location","stableKeys":["ecommerce.feature.warehouse-admin.warehouse-view.7b"]},{"id":"unauthenticated-direct-purchase-uses-default-account","stableKeys":["ecommerce.spec.access-control.purchase-session.101a"]},{"id":"direct-purchase-is-attributed-to-previous-account","stableKeys":["ecommerce.spec.access-control.purchase-attribution.102a"]},{"id":"direct-purchase-uses-constant-price","stableKeys":["ecommerce.spec.transactional-integrity.server-price.104a"]},{"id":"account-state-reload-discards-session","stableKeys":["ecommerce.spec.state-durability.account-state-recovery.105a"]},{"id":"offline-event-clears-account-state","stableKeys":["ecommerce.spec.state-durability.account-state-recovery.105b"]},{"id":"purchase-does-not-decrement-warehouse-stock","stableKeys":["ecommerce.spec.transactional-integrity.books-balance.107b"]},{"id":"review-route-skips-purchase-eligibility","stableKeys":["ecommerce.spec.access-control.review-eligibility.108a"]},{"id":"only-shipped-orders-earn-review-eligibility","stableKeys":["ecommerce.spec.access-control.review-eligibility.108b","ecommerce.spec.access-control.review-eligibility.108a"]},{"id":"cart-update-accepts-negative-quantity","stableKeys":["ecommerce.spec.access-control.cart-boundary.109b"]},{"id":"oversell-no-row-lock","stableKeys":["ecommerce.spec.concurrency-safety.last-unit.201a","ecommerce.spec.concurrency-safety.last-unit.201b","ecommerce.spec.concurrency-safety.last-unit.201c"]},{"id":"purchase-read-write-loses-concurrent-stock","stableKeys":["ecommerce.spec.concurrency-safety.restock-race.202a"]},{"id":"external-stock-polling-disabled","stableKeys":["ecommerce.spec.external-data-sync.external-stock.901a"]},{"id":"server-restart-does-not-resynchronize-catalog","stableKeys":["ecommerce.spec.external-data-sync.external-stock.901c"]},{"id":"reconnect-does-not-send-current-catalog","stableKeys":["ecommerce.spec.external-data-sync.external-stock.901d"]},{"id":"open-review-list-ignores-live-update","stableKeys":["ecommerce.spec.live-state.open-list.902a"]},{"id":"open-review-list-renders-each-review-twice","stableKeys":["ecommerce.spec.live-state.open-list.902a"]},{"id":"cancel-does-not-restore-stock-feature","stableKeys":["ecommerce.returns-pricing.cancellation-and-return.3a"]},{"id":"cancellation-accounting-loses-stock-restoration","stableKeys":["ecommerce.returns-pricing.refund-accounting.203a"]},{"id":"cancel-does-not-restore-stock-fresh-client","stableKeys":["ecommerce.inventory-operations.stock-conservation.202b","ecommerce.inventory-operations.stock-conservation.202c"]},{"id":"cancel-restores-stock-but-keeps-pending-status","stableKeys":["ecommerce.returns-pricing.cancellation-and-return.3b"]},{"id":"operator-authorization-allows-customer-transfer","stableKeys":["ecommerce.operations-access.operator-authorization.201a"]},{"id":"customer-can-ship-order-direct-1-1","stableKeys":["ecommerce.operations-access.operator-authorization.201c"]},{"id":"customer-can-cancel-foreign-order-1-1","stableKeys":["ecommerce.operations-access.order-owner.204a"]},{"id":"progression-customer-sees-fulfilment-content","stableKeys":["ecommerce.spec.access-control.fulfilment-area-boundary.1d"]},{"id":"transfer-debits-source-without-crediting-existing-destination","stableKeys":["ecommerce.inventory-operations.stock-conservation.202a","ecommerce.inventory-operations.warehouse-transfer.2a","ecommerce.operations-access.operator-authorization.201a"]},{"id":"recommendations-ignore-pending-purchases","stableKeys":["ecommerce.inventory-operations.operational-views.5c"]},{"id":"purchases-do-not-affect-best-sellers","stableKeys":["ecommerce.inventory-operations.operational-views.5d"]},{"id":"queue-warehouse-reports-west","stableKeys":["ecommerce.operations-access.fulfilment-queue.1b"]},{"id":"transfer-overwrites-concurrent-purchase-with-stale-stock","stableKeys":["ecommerce.inventory-operations.stock-conservation.202d"]},{"id":"progression-profile-address-is-discarded","stableKeys":["ecommerce.spec.state-durability.customer-profile-reload.620a"]},{"id":"progression-profile-reads-another-account","stableKeys":["ecommerce.spec.access-control.customer-profile-privacy.620b"]},{"id":"progression-staff-tools-are-hidden","stableKeys":["ecommerce.progression.staff-access.staff-access.601a"]},{"id":"progression-customer-sees-staff-tools","stableKeys":["ecommerce.spec.access-control.staff-area-boundary.601b"]},{"id":"progression-staff-role-is-lost-on-restart","stableKeys":["ecommerce.spec.state-durability.staff-role-reload.621a"]},{"id":"staff-role-write-precedes-denial","stableKeys":["ecommerce.spec.access-control.staff-role-boundary.621b","ecommerce.spec.access-control.staff-role-revocation.621d"]},{"id":"progression-staff-can-assign-roles","stableKeys":["ecommerce.spec.access-control.staff-role-boundary.621b","ecommerce.spec.access-control.staff-role-revocation.621d"]},{"id":"progression-catalog-product-name-is-not-published","stableKeys":["ecommerce.progression.catalog-management.catalog-management.622a","ecommerce.progression.catalog-management.catalog-management.622b"]},{"id":"progression-catalog-variants-are-discarded","stableKeys":["ecommerce.progression.catalog-management.catalog-management.622b"]},{"id":"progression-support-intake-is-disabled","stableKeys":["ecommerce.progression.support-intake.support-intake.610a"]},{"id":"progression-support-triage-update-is-disabled","stableKeys":["ecommerce.progression.support-triage.support-assignment.611a","ecommerce.progression.support-triage.support-priority.611b","ecommerce.progression.support-triage.support-status.611c"]},{"id":"progression-support-history-is-not-persisted","stableKeys":["ecommerce.spec.state-durability.support-history-reload.612a"]},{"id":"progression-support-history-leaks","stableKeys":["ecommerce.spec.access-control.support-history-privacy.612b"]},{"id":"progression-managed-support-is-not-shared","stableKeys":["ecommerce.spec.live-state.managed-support.613a"]},{"id":"progression-managed-support-leaks","stableKeys":["ecommerce.spec.access-control.managed-support-privacy.613b"]},{"id":"progression-promotion-discount-is-offset","stableKeys":["ecommerce.progression.promotion-rules.promotion-rule-values.620a"]},{"id":"progression-customer-can-create-promotions","stableKeys":["ecommerce.spec.access-control.promotion-management-boundary.620b"]},{"id":"progression-notification-preferences-do-not-save","stableKeys":["ecommerce.spec.state-durability.notification-preferences-reload.630a"]},{"id":"progression-notifications-leak-across-accounts","stableKeys":["ecommerce.spec.access-control.notification-preferences-privacy.630b"]},{"id":"stock-alert-delivery-is-suppressed","stableKeys":["ecommerce.progression.stock-alerts.stock-alert-delivery.631c"]},{"id":"stock-alert-is-sent-after-every-restock","stableKeys":["ecommerce.spec.transactional-integrity.stock-alert-deduplication.631a"]},{"id":"progression-stock-alerts-leak-across-accounts","stableKeys":["ecommerce.spec.access-control.stock-alert-privacy.631b"]},{"id":"progression-faceted-filter-ignores-category","stableKeys":["ecommerce.progression.faceted-search.faceted-search.401a"]},{"id":"active-search-uses-purchase-ranking","stableKeys":["ecommerce.spec.search-ordering.search-ordering.402b"]},{"id":"progression-pagination-always-shows-first-page","stableKeys":["ecommerce.progression.faceted-search.faceted-search.402a"]},{"id":"progression-restock-countdown-is-fixed","stableKeys":["ecommerce.l3.scheduled-restocks.scheduled-restocks.302a"]},{"id":"progression-due-restock-does-not-run","stableKeys":["ecommerce.l3.scheduled-restocks.scheduled-restocks.305a"]},{"id":"progression-cancelled-restock-still-runs","stableKeys":["ecommerce.l3.scheduled-restocks.scheduled-restocks.306a"]},{"id":"progression-restart-timer-never-runs","stableKeys":["ecommerce.l3.server-time.server-time.312a"]},{"id":"progression-cart-line-does-not-increment","stableKeys":["ecommerce.feature.cart-checkout.cart.4a"]},{"id":"progression-checkout-leaves-cart-lines","stableKeys":["ecommerce.feature.cart-checkout.cart.4d"]},{"id":"progression-cart-update-uses-wrong-room","stableKeys":["ecommerce.spec.live-state.shared-cart.4c"]},{"id":"progression-order-history-ignores-owner","stableKeys":["ecommerce.spec.access-control.order-ownership.106a"]},{"id":"progression-review-conflict-is-not-updated","stableKeys":["ecommerce.spec.transactional-integrity.unique-review.6b"]},{"id":"progression-revenue-double-counts-orders","stableKeys":["ecommerce.spec.transactional-integrity.books-balance.107a"]},{"id":"progression-cancelled-orders-remain-in-revenue","stableKeys":["ecommerce.returns-pricing.refund-accounting.203a"]},{"id":"progression-shipping-keeps-order-pending","stableKeys":["ecommerce.operations-access.fulfilment-queue.1c"]},{"id":"progression-concurrent-cart-line-does-not-increment","stableKeys":["ecommerce.spec.concurrency-safety.duplicate-checkout.203a"]},{"id":"progression-concurrent-checkout-leaves-cart-lines","stableKeys":["ecommerce.spec.concurrency-safety.duplicate-checkout.203b"]},{"id":"progression-catalog-ranking-is-reversed","stableKeys":["ecommerce.feature.catalog.catalog-ranking.2b"]},{"id":"progression-catalog-search-requires-exact-name","stableKeys":["ecommerce.feature.catalog.catalog-search.2d"]},{"id":"progression-catalog-price-is-offset","stableKeys":["ecommerce.feature.catalog.catalog-values.2a"]},{"id":"progression-staff-sees-admin-navigation","stableKeys":["ecommerce.spec.access-control.warehouse-area-boundary.7a"]},{"id":"progression-staff-can-restock-directly","stableKeys":["ecommerce.spec.access-control.warehouse-write-boundary.103b"]},{"id":"progression-restock-adds-wrong-quantity","stableKeys":["ecommerce.spec.live-state.warehouse-stock.7c"]},{"id":"progression-cart-add-uses-another-account","stableKeys":["ecommerce.spec.access-control.cart-boundary.109a"]},{"id":"progression-customers-can-manage-scheduled-work","stableKeys":["ecommerce.l3.deferred-access.scheduled-work-access.317a"]},{"id":"progression-restock-does-not-survive-restart","stableKeys":["ecommerce.l3.deferred-durability.restart-survival.311a"]},{"id":"progression-restock-can-apply-more-than-once","stableKeys":["ecommerce.l3.deferred-integrity.exactly-once.311a"]},{"id":"restock-overwrites-instead-of-increments","stableKeys":["ecommerce.spec.live-state.warehouse-stock.7c"]},{"id":"direct-review-access-is-not-checked","stableKeys":["ecommerce.progression.review-access-specifications.review-eligibility-direct.618a"]},{"id":"support-history-rows-are-hidden","stableKeys":["ecommerce.progression.support-history.support-history.612c","ecommerce.spec.state-durability.support-history-reload.612a","ecommerce.spec.access-control.support-history-privacy.612b","ecommerce.spec.access-control.support-history-logout.612d"]},{"id":"authorized-restock-does-not-change-stock","stableKeys":["ecommerce.feature.warehouse-admin.admin-write.103a"]},{"id":"low-stock-threshold-is-two-units","stableKeys":["ecommerce.inventory-operations.operational-views.5e","ecommerce.spec.live-state.inventory-dashboard.5a"]},{"id":"category-totals-render-as-session-deltas","stableKeys":["ecommerce.inventory-operations.operational-views.5f"]},{"id":"profile-summary-ignores-saved-address","stableKeys":["ecommerce.progression.customer-profile.customer-profile.620c"]},{"id":"support-first-reply-is-hidden","stableKeys":["ecommerce.progression.managed-support.managed-support.613c"]},{"id":"notification-sync-flips-saved-toggle","stableKeys":["ecommerce.progression.notification-preferences.notification-preferences.630c"]},{"id":"staff-role-form-reverts-after-save","stableKeys":["ecommerce.progression.staff-roles.staff-roles.621c"]},{"id":"purchase-does-not-broadcast-fulfilment-queue","stableKeys":["ecommerce.spec.live-state.fulfilment-queue.1a"]},{"id":"admin-state-change-is-not-broadcast","stableKeys":["ecommerce.spec.live-state.inventory-dashboard.5a"]},{"id":"admin-sockets-do-not-join-admin-room","stableKeys":["ecommerce.spec.live-state.sales-dashboard.5b"]},{"id":"transfer-overdraft-guard-skips-bulk-transfers","stableKeys":["ecommerce.spec.transactional-integrity.stock-transfer-overdraw.2c"]},{"id":"transfer-does-not-publish-warehouse-totals","stableKeys":["ecommerce.spec.live-state.stock-transfers.2b"]},{"id":"progression-support-history-anonymous-leak","stableKeys":["ecommerce.spec.access-control.support-history-logout.612d"]},{"id":"checkout-crash-integrity","stableKeys":["ecommerce.spec.state-durability.checkout-crash-integrity.910a"]},{"id":"checkout-crash-durability","stableKeys":["ecommerce.spec.state-durability.checkout-crash-durability.910b"]},{"id":"review-script-unsafe-render","stableKeys":["ecommerce.progression.review-access-specifications.stored-review-script.9180a"]},{"id":"review-script-reject-all","stableKeys":["ecommerce.progression.review-access-specifications.stored-review-script.9180a"]}]},{"backend":"spacetime","path":"grader/mutations/spacetime-ecommerce.json","sha256":"158212f01a8b0bfd29976eed0361855bcb1ffbd71f00e4bb22707695098efcba","referenceId":"ecommerce-reference-spacetime","executionSha256":"c845a507863287e3a900498d1cca31e058f1b745bc1b5d8ba048ba79e0734e23","targets":[{"id":"staff-admin-access-survives-role-removal","stableKeys":["ecommerce.spec.access-control.staff-role-revocation.621d"]},{"id":"shipping-counts-sale-twice","stableKeys":["ecommerce.inventory-operations.shipping-accounting.202e"]},{"id":"restock-client-snapshot-overwrites-concurrent-purchases","stableKeys":["ecommerce.spec.concurrency-safety.restock-race.202a"]},{"id":"signup-binds-the-new-account-to-the-admin-session","stableKeys":["ecommerce.feature.accounts.accounts.1a"]},{"id":"duplicate-signup-is-silently-ignored","stableKeys":["ecommerce.feature.accounts.accounts.1b"]},{"id":"signin-does-not-verify-the-password","stableKeys":["ecommerce.feature.accounts.accounts.1c"]},{"id":"signout-keeps-the-account-session","stableKeys":["ecommerce.feature.accounts.accounts.1d"]},{"id":"session-token-is-not-persisted-for-reload","stableKeys":["ecommerce.spec.state-durability.session-reload.1e"]},{"id":"catalog-seeds-the-wrong-air-purifier-price","stableKeys":["ecommerce.feature.catalog.catalog-values.2a"]},{"id":"catalog-tie-breaks-in-reverse-alphabetical-order--01-catalog-ranking","stableKeys":["ecommerce.feature.catalog.catalog-ranking.2b"]},{"id":"catalog-tie-breaks-in-reverse-alphabetical-order--01-core","stableKeys":["ecommerce.spec.live-state.ranking.2c"]},{"id":"purchase-does-not-update-ranking-count","stableKeys":["ecommerce.spec.live-state.ranking.2c"]},{"id":"signed-out-purchase-bypasses-account-check","stableKeys":["ecommerce.spec.access-control.signed-out-purchase.3a"]},{"id":"buy-now-creates-orders-without-reserving-stock--01-buying","stableKeys":["ecommerce.spec.live-state.purchase-stock.3b"]},{"id":"restock-race-records-wrong-order-total","stableKeys":["ecommerce.spec.concurrency-safety.restock-race.202a"]},{"id":"buy-now-records-the-wrong-order-total","stableKeys":["ecommerce.feature.purchasing.purchase-order.3c"]},{"id":"existing-cart-line-does-not-increment-basic-cart","stableKeys":["ecommerce.feature.cart-checkout.cart.4a"]},{"id":"cart-is-deleted-when-owner-disconnects","stableKeys":["ecommerce.spec.state-durability.cart-reload.4b"]},{"id":"signin-binds-the-second-client-to-a-different-account","stableKeys":["ecommerce.spec.live-state.shared-cart.4c"]},{"id":"checkout-does-not-empty-the-basic-cart","stableKeys":["ecommerce.feature.cart-checkout.cart.4d"]},{"id":"new-review-is-accepted-without-being-stored","stableKeys":["ecommerce.feature.reviews.reviews.6a"]},{"id":"repeat-review-inserts-a-second-row","stableKeys":["ecommerce.spec.transactional-integrity.unique-review.6b"]},{"id":"review-average-counts-rows-instead-of-ratings","stableKeys":["ecommerce.spec.live-state.rating.6c"]},{"id":"every-signed-in-customer-is-treated-as-an-admin","stableKeys":["ecommerce.spec.access-control.warehouse-area-boundary.7a"]},{"id":"warehouse-view-omits-west","stableKeys":["ecommerce.feature.warehouse-admin.warehouse-view.7b"]},{"id":"guest-purchase-falls-back-to-the-admin-account","stableKeys":["ecommerce.spec.access-control.purchase-session.101a"]},{"id":"direct-purchases-are-attributed-to-the-system-account","stableKeys":["ecommerce.spec.access-control.purchase-attribution.102a"]},{"id":"direct-restock-does-not-require-an-admin","stableKeys":["ecommerce.spec.access-control.warehouse-write-boundary.103b"]},{"id":"direct-purchase-ignores-the-stored-price","stableKeys":["ecommerce.spec.transactional-integrity.server-price.104a"]},{"id":"account-state-token-is-not-restored-after-reload","stableKeys":["ecommerce.spec.state-durability.account-state-recovery.105a"]},{"id":"reconnect-discards-the-visible-account-state","stableKeys":["ecommerce.spec.state-durability.account-state-recovery.105b"]},{"id":"order-views-return-every-customers-orders","stableKeys":["ecommerce.spec.access-control.order-ownership.106a"]},{"id":"admin-revenue-double-counts-every-order","stableKeys":["ecommerce.spec.transactional-integrity.books-balance.107a"]},{"id":"purchases-do-not-leave-the-warehouses","stableKeys":["ecommerce.spec.transactional-integrity.books-balance.107b"]},{"id":"review-purchase-eligibility-is-not-checked","stableKeys":["ecommerce.spec.access-control.review-eligibility.108a"]},{"id":"eligible-review-is-accepted-without-being-stored","stableKeys":["ecommerce.spec.access-control.review-eligibility.108b","ecommerce.spec.access-control.review-eligibility.108a"]},{"id":"cart-line-lookup-ignores-cart-ownership","stableKeys":["ecommerce.spec.access-control.cart-boundary.109a"]},{"id":"purchase-does-not-reserve-stock-last-unit","stableKeys":["ecommerce.spec.concurrency-safety.last-unit.201a","ecommerce.spec.concurrency-safety.last-unit.201b","ecommerce.spec.concurrency-safety.last-unit.201c"]},{"id":"existing-cart-line-does-not-increment","stableKeys":["ecommerce.spec.concurrency-safety.duplicate-checkout.203a"]},{"id":"checkout-does-not-empty-cart","stableKeys":["ecommerce.spec.concurrency-safety.duplicate-checkout.203b"]},{"id":"stock-subscription-snapshotted-once","stableKeys":["ecommerce.spec.external-data-sync.external-stock.901a"]},{"id":"stock-view-ignores-update-across-app-server-stop","stableKeys":["ecommerce.spec.external-data-sync.external-stock.901c"]},{"id":"stock-view-keeps-pre-reconnect-snapshot","stableKeys":["ecommerce.spec.external-data-sync.external-stock.901d"]},{"id":"open-review-list-snapshots-on-selection","stableKeys":["ecommerce.spec.live-state.open-list.902a"]},{"id":"open-review-list-renders-each-review-twice","stableKeys":["ecommerce.spec.live-state.open-list.902a"]},{"id":"cancel-does-not-restore-stock-feature","stableKeys":["ecommerce.returns-pricing.cancellation-and-return.3a"]},{"id":"cancellation-accounting-loses-stock-restoration","stableKeys":["ecommerce.returns-pricing.refund-accounting.203a"]},{"id":"cancel-does-not-restore-stock-fresh-client","stableKeys":["ecommerce.inventory-operations.stock-conservation.202b","ecommerce.inventory-operations.stock-conservation.202c"]},{"id":"cancel-restores-stock-but-keeps-pending-status","stableKeys":["ecommerce.returns-pricing.cancellation-and-return.3b"]},{"id":"cancelled-order-remains-in-revenue-feature","stableKeys":["ecommerce.returns-pricing.cancellation-and-return.3a"]},{"id":"cancelled-order-remains-in-revenue-invariant","stableKeys":["ecommerce.returns-pricing.refund-accounting.203a"]},{"id":"operator-authorization-allows-customer-transfer","stableKeys":["ecommerce.operations-access.operator-authorization.201a"]},{"id":"customer-can-ship-order-direct-1-1","stableKeys":["ecommerce.operations-access.operator-authorization.201c"]},{"id":"customer-can-cancel-foreign-order-1-1","stableKeys":["ecommerce.operations-access.order-owner.204a"]},{"id":"ship-acknowledges-without-changing-status","stableKeys":["ecommerce.operations-access.fulfilment-queue.1c"]},{"id":"progression-customer-sees-fulfilment-content","stableKeys":["ecommerce.spec.access-control.fulfilment-area-boundary.1d"]},{"id":"operator-authorization-allows-customer-shipping","stableKeys":["ecommerce.operations-access.operator-authorization.201c"]},{"id":"transfer-debits-source-without-crediting-existing-destination","stableKeys":["ecommerce.inventory-operations.stock-conservation.202a","ecommerce.inventory-operations.warehouse-transfer.2a","ecommerce.operations-access.operator-authorization.201a"]},{"id":"recommendations-ignore-pending-purchases","stableKeys":["ecommerce.inventory-operations.operational-views.5c"]},{"id":"purchases-do-not-affect-best-sellers","stableKeys":["ecommerce.inventory-operations.operational-views.5d"]},{"id":"queue-warehouse-reports-west","stableKeys":["ecommerce.operations-access.fulfilment-queue.1b"]},{"id":"transfer-creates-stock-during-race","stableKeys":["ecommerce.inventory-operations.stock-conservation.202d"]},{"id":"catalog-search-ignores-the-query","stableKeys":["ecommerce.feature.catalog.catalog-search.2d"]},{"id":"admin-total-stock-is-not-rendered","stableKeys":["ecommerce.spec.live-state.warehouse-stock.7c"]},{"id":"customers-can-schedule-restocks","stableKeys":["ecommerce.l3.deferred-access.scheduled-work-access.317a"]},{"id":"scheduled-restock-execution-queue-is-process-local","stableKeys":["ecommerce.l3.deferred-durability.restart-survival.311a"]},{"id":"completed-restock-remains-pending","stableKeys":["ecommerce.l3.deferred-integrity.exactly-once.311a"]},{"id":"pending-restock-timer-is-static","stableKeys":["ecommerce.l3.scheduled-restocks.scheduled-restocks.302a"]},{"id":"due-restock-omits-ledger-entry","stableKeys":["ecommerce.l3.scheduled-restocks.scheduled-restocks.305a"]},{"id":"cancelled-restock-remains-pending","stableKeys":["ecommerce.l3.scheduled-restocks.scheduled-restocks.306a"]},{"id":"restart-restock-runs-early","stableKeys":["ecommerce.l3.server-time.server-time.312a"]},{"id":"catalog-product-is-not-published","stableKeys":["ecommerce.progression.catalog-management.catalog-management.622a","ecommerce.progression.catalog-management.catalog-management.622b"]},{"id":"catalog-variants-are-discarded","stableKeys":["ecommerce.progression.catalog-management.catalog-management.622b"]},{"id":"profile-is-lost-on-fresh-account-login","stableKeys":["ecommerce.spec.state-durability.customer-profile-reload.620a"]},{"id":"customer-profile-view-leaks-another-account","stableKeys":["ecommerce.spec.access-control.customer-profile-privacy.620b"]},{"id":"faceted-search-ignores-category","stableKeys":["ecommerce.progression.faceted-search.faceted-search.401a"]},{"id":"active-search-uses-purchase-ranking","stableKeys":["ecommerce.spec.search-ordering.search-ordering.402b"]},{"id":"faceted-search-next-page-does-not-advance","stableKeys":["ecommerce.progression.faceted-search.faceted-search.402a"]},{"id":"managed-support-leaks-and-accepts-cross-account-replies","stableKeys":["ecommerce.spec.access-control.managed-support-privacy.613b"]},{"id":"managed-support-replies-are-empty","stableKeys":["ecommerce.spec.live-state.managed-support.613a","ecommerce.progression.managed-support.managed-support.613c"]},{"id":"managed-support-live-replies-stay-at-initial-snapshot","stableKeys":["ecommerce.spec.live-state.managed-support.613a"]},{"id":"notification-preferences-are-not-saved","stableKeys":["ecommerce.spec.state-durability.notification-preferences-reload.630a"]},{"id":"notification-preferences-leak-across-accounts","stableKeys":["ecommerce.spec.access-control.notification-preferences-privacy.630b"]},{"id":"customers-can-create-promotions","stableKeys":["ecommerce.spec.access-control.promotion-management-boundary.620b"]},{"id":"promotion-rule-stores-the-wrong-discount","stableKeys":["ecommerce.progression.promotion-rules.promotion-rule-values.620a"]},{"id":"staff-cannot-open-staff-tools","stableKeys":["ecommerce.progression.staff-access.staff-access.601a"]},{"id":"customers-can-open-staff-tools","stableKeys":["ecommerce.spec.access-control.staff-area-boundary.601b"]},{"id":"administrator-role-assignment-is-discarded","stableKeys":["ecommerce.spec.state-durability.staff-role-reload.621a"]},{"id":"staff-can-assign-roles","stableKeys":["ecommerce.spec.access-control.staff-role-boundary.621b","ecommerce.spec.access-control.staff-role-revocation.621d"]},{"id":"stock-alert-delivery-is-suppressed","stableKeys":["ecommerce.progression.stock-alerts.stock-alert-delivery.631c"]},{"id":"stock-alert-is-sent-after-every-restock","stableKeys":["ecommerce.spec.transactional-integrity.stock-alert-deduplication.631a"]},{"id":"stock-alerts-are-visible-to-other-customers","stableKeys":["ecommerce.spec.access-control.stock-alert-privacy.631b"]},{"id":"support-history-is-lost-on-fresh-account-login","stableKeys":["ecommerce.spec.state-durability.support-history-reload.612a"]},{"id":"support-history-leaks-across-customers","stableKeys":["ecommerce.spec.access-control.support-history-privacy.612b","ecommerce.spec.access-control.support-history-logout.612d"]},{"id":"visitor-support-reference-is-hidden","stableKeys":["ecommerce.progression.support-intake.support-intake.610a"]},{"id":"support-assignment-is-discarded","stableKeys":["ecommerce.progression.support-triage.support-assignment.611a"]},{"id":"support-priority-is-discarded","stableKeys":["ecommerce.progression.support-triage.support-priority.611b"]},{"id":"support-status-is-discarded","stableKeys":["ecommerce.progression.support-triage.support-status.611c"]},{"id":"nonpositive-cart-quantity-is-treated-as-removal","stableKeys":["ecommerce.spec.access-control.cart-boundary.109b"]},{"id":"admin-restock-preserves-existing-stock","stableKeys":["ecommerce.spec.live-state.warehouse-stock.7c"]},{"id":"direct-review-access-is-not-checked","stableKeys":["ecommerce.progression.review-access-specifications.review-eligibility-direct.618a"]},{"id":"support-history-rows-are-hidden","stableKeys":["ecommerce.progression.support-history.support-history.612c","ecommerce.spec.state-durability.support-history-reload.612a","ecommerce.spec.access-control.support-history-privacy.612b","ecommerce.spec.access-control.support-history-logout.612d"]},{"id":"authorized-restock-does-not-change-stock","stableKeys":["ecommerce.feature.warehouse-admin.admin-write.103a"]},{"id":"low-stock-threshold-is-two-units","stableKeys":["ecommerce.inventory-operations.operational-views.5e","ecommerce.spec.live-state.inventory-dashboard.5a"]},{"id":"category-totals-count-only-since-the-dashboard-opened","stableKeys":["ecommerce.inventory-operations.operational-views.5f"]},{"id":"profile-summary-ignores-a-profile-saved-this-session","stableKeys":["ecommerce.progression.customer-profile.customer-profile.620c"]},{"id":"stored-support-replies-are-hidden-after-reload","stableKeys":["ecommerce.progression.managed-support.managed-support.613c"]},{"id":"saving-notification-preferences-resets-the-toggles","stableKeys":["ecommerce.progression.notification-preferences.notification-preferences.630c"]},{"id":"saving-a-staff-role-snaps-the-input-back-to-the-stored-role","stableKeys":["ecommerce.progression.staff-roles.staff-roles.621c"]},{"id":"fulfilment-queue-is-frozen-at-page-load","stableKeys":["ecommerce.spec.live-state.fulfilment-queue.1a"]},{"id":"low-stock-list-is-frozen-at-page-load","stableKeys":["ecommerce.spec.live-state.inventory-dashboard.5a"]},{"id":"category-totals-are-frozen-at-page-load","stableKeys":["ecommerce.spec.live-state.sales-dashboard.5b"]},{"id":"warehouse-totals-are-frozen-at-page-load","stableKeys":["ecommerce.spec.live-state.stock-transfers.2b"]},{"id":"transfer-skips-the-source-holding-check","stableKeys":["ecommerce.spec.transactional-integrity.stock-transfer-overdraw.2c"]},{"id":"support-history-leaks-to-signed-out-visitors","stableKeys":["ecommerce.spec.access-control.support-history-logout.612d"]},{"id":"checkout-crash-integrity","stableKeys":["ecommerce.spec.state-durability.checkout-crash-integrity.910a"]},{"id":"checkout-crash-durability","stableKeys":["ecommerce.spec.state-durability.checkout-crash-durability.910b"]},{"id":"review-script-unsafe-render","stableKeys":["ecommerce.progression.review-access-specifications.stored-review-script.9180a"]},{"id":"review-script-reject-all","stableKeys":["ecommerce.progression.review-access-specifications.stored-review-script.9180a"]}]}],"nullControl":{"pointBearing":"must-fail-conclusively","repetitions":1,"zeroPoint":"typed-policy"},"qualification":{"exactCombinationRequired":true,"referenceRepetitions":1,"mutationRepetitions":1,"checks":["ecommerce.feature.accounts.accounts.1a","ecommerce.feature.accounts.accounts.1b","ecommerce.feature.accounts.accounts.1c","ecommerce.feature.accounts.accounts.1d","ecommerce.feature.cart-checkout.cart.4a","ecommerce.feature.cart-checkout.cart.4d","ecommerce.feature.catalog.catalog-ranking.2b","ecommerce.feature.catalog.catalog-search.2d","ecommerce.feature.catalog.catalog-values.2a","ecommerce.feature.purchasing.purchase-order.3c","ecommerce.feature.reviews.reviews.6a","ecommerce.feature.warehouse-admin.admin-write.103a","ecommerce.feature.warehouse-admin.warehouse-view.7b","ecommerce.inventory-operations.operational-views.5c","ecommerce.inventory-operations.operational-views.5d","ecommerce.inventory-operations.operational-views.5e","ecommerce.inventory-operations.operational-views.5f","ecommerce.inventory-operations.shipping-accounting.202e","ecommerce.inventory-operations.stock-conservation.202a","ecommerce.inventory-operations.stock-conservation.202b","ecommerce.inventory-operations.stock-conservation.202c","ecommerce.inventory-operations.stock-conservation.202d","ecommerce.inventory-operations.warehouse-transfer.2a","ecommerce.l3.deferred-access.scheduled-work-access.317a","ecommerce.l3.deferred-durability.restart-survival.311a","ecommerce.l3.deferred-integrity.exactly-once.311a","ecommerce.l3.scheduled-restocks.scheduled-restocks.302a","ecommerce.l3.scheduled-restocks.scheduled-restocks.305a","ecommerce.l3.scheduled-restocks.scheduled-restocks.306a","ecommerce.l3.server-time.server-time.312a","ecommerce.operations-access.fulfilment-queue.1b","ecommerce.operations-access.fulfilment-queue.1c","ecommerce.operations-access.operator-authorization.201a","ecommerce.operations-access.operator-authorization.201c","ecommerce.operations-access.order-owner.204a","ecommerce.progression.catalog-management.catalog-management.622a","ecommerce.progression.catalog-management.catalog-management.622b","ecommerce.progression.customer-profile.customer-profile.620c","ecommerce.progression.faceted-search.faceted-search.401a","ecommerce.progression.faceted-search.faceted-search.402a","ecommerce.progression.managed-support.managed-support.613c","ecommerce.progression.notification-preferences.notification-preferences.630c","ecommerce.progression.promotion-rules.promotion-rule-values.620a","ecommerce.progression.review-access-specifications.review-eligibility-direct.618a","ecommerce.progression.review-access-specifications.stored-review-script.9180a","ecommerce.progression.staff-access.staff-access.601a","ecommerce.progression.staff-roles.staff-roles.621c","ecommerce.progression.stock-alerts.stock-alert-delivery.631c","ecommerce.progression.support-history.support-history.612c","ecommerce.progression.support-intake.support-intake.610a","ecommerce.progression.support-triage.support-assignment.611a","ecommerce.progression.support-triage.support-priority.611b","ecommerce.progression.support-triage.support-status.611c","ecommerce.returns-pricing.cancellation-and-return.3a","ecommerce.returns-pricing.cancellation-and-return.3b","ecommerce.returns-pricing.refund-accounting.203a","ecommerce.spec.access-control.cart-boundary.109a","ecommerce.spec.access-control.cart-boundary.109b","ecommerce.spec.access-control.customer-profile-privacy.620b","ecommerce.spec.access-control.fulfilment-area-boundary.1d","ecommerce.spec.access-control.managed-support-privacy.613b","ecommerce.spec.access-control.notification-preferences-privacy.630b","ecommerce.spec.access-control.order-ownership.106a","ecommerce.spec.access-control.promotion-management-boundary.620b","ecommerce.spec.access-control.purchase-attribution.102a","ecommerce.spec.access-control.purchase-session.101a","ecommerce.spec.access-control.review-eligibility.108a","ecommerce.spec.access-control.review-eligibility.108b","ecommerce.spec.access-control.signed-out-purchase.3a","ecommerce.spec.access-control.staff-area-boundary.601b","ecommerce.spec.access-control.staff-role-boundary.621b","ecommerce.spec.access-control.staff-role-revocation.621d","ecommerce.spec.access-control.stock-alert-privacy.631b","ecommerce.spec.access-control.support-history-logout.612d","ecommerce.spec.access-control.support-history-privacy.612b","ecommerce.spec.access-control.warehouse-area-boundary.7a","ecommerce.spec.access-control.warehouse-write-boundary.103b","ecommerce.spec.concurrency-safety.duplicate-checkout.203a","ecommerce.spec.concurrency-safety.duplicate-checkout.203b","ecommerce.spec.concurrency-safety.last-unit.201a","ecommerce.spec.concurrency-safety.last-unit.201b","ecommerce.spec.concurrency-safety.last-unit.201c","ecommerce.spec.concurrency-safety.restock-race.202a","ecommerce.spec.external-data-sync.external-stock.901a","ecommerce.spec.external-data-sync.external-stock.901c","ecommerce.spec.external-data-sync.external-stock.901d","ecommerce.spec.live-state.fulfilment-queue.1a","ecommerce.spec.live-state.inventory-dashboard.5a","ecommerce.spec.live-state.managed-support.613a","ecommerce.spec.live-state.open-list.902a","ecommerce.spec.live-state.purchase-stock.3b","ecommerce.spec.live-state.ranking.2c","ecommerce.spec.live-state.rating.6c","ecommerce.spec.live-state.sales-dashboard.5b","ecommerce.spec.live-state.shared-cart.4c","ecommerce.spec.live-state.stock-transfers.2b","ecommerce.spec.live-state.warehouse-stock.7c","ecommerce.spec.search-ordering.search-ordering.402b","ecommerce.spec.state-durability.account-state-recovery.105a","ecommerce.spec.state-durability.account-state-recovery.105b","ecommerce.spec.state-durability.cart-reload.4b","ecommerce.spec.state-durability.checkout-crash-durability.910b","ecommerce.spec.state-durability.checkout-crash-integrity.910a","ecommerce.spec.state-durability.customer-profile-reload.620a","ecommerce.spec.state-durability.notification-preferences-reload.630a","ecommerce.spec.state-durability.session-reload.1e","ecommerce.spec.state-durability.staff-role-reload.621a","ecommerce.spec.state-durability.support-history-reload.612a","ecommerce.spec.transactional-integrity.books-balance.107a","ecommerce.spec.transactional-integrity.books-balance.107b","ecommerce.spec.transactional-integrity.server-price.104a","ecommerce.spec.transactional-integrity.stock-alert-deduplication.631a","ecommerce.spec.transactional-integrity.stock-transfer-overdraw.2c","ecommerce.spec.transactional-integrity.unique-review.6b"],"runner":{"schemaVersion":1,"mode":"appliance","platform":"linux","architecture":"x64"},"stacks":["mongodb","postgres","spacetime"],"evidence":[{"kind":"null","repetition":1,"path":"qualification-evidence/ecommerce-l3-7cd96d01b/null.json","sha256":"208efdd6b111d7769c6a03d96786057e4042ae1e6531e3d7bfea2b609cb8c46a"},{"kind":"reference","stack":"postgres","repetition":1,"path":"qualification-evidence/ecommerce-l3-7cd96d01b/postgres-reference.json","sha256":"baaba1487f36fa51907c8ff4fc866997fc2625097e7fe333b3d2250801ed9baf"},{"kind":"mutation","stack":"postgres","repetition":1,"path":"qualification-evidence/ecommerce-l3-7cd96d01b/postgres-mutation.json","sha256":"37ee3c783660a96f44bc9a9f8c5f58968972d0e1a3f8137779720bbaa4fb0f3b"},{"kind":"reference","stack":"mongodb","repetition":1,"path":"qualification-evidence/ecommerce-l3-7cd96d01b/mongodb-reference.json","sha256":"9cef5bf86b29d0ce519fe5b1e05f8596af65518619974b0d64af174ac567dda4"},{"kind":"mutation","stack":"mongodb","repetition":1,"path":"qualification-evidence/ecommerce-l3-7cd96d01b/mongodb-mutation.json","sha256":"2d81f1ab1d611701e6a0c280e4f3f9368bc81932afe6e95e7a84bbda1a00a613"},{"kind":"reference","stack":"spacetime","repetition":1,"path":"qualification-evidence/ecommerce-l3-7cd96d01b/spacetime-reference.json","sha256":"83989faa0da22b7a2bb13e491476813a40be352d08bd79ac617f10d980b26095"},{"kind":"mutation","stack":"spacetime","repetition":1,"path":"qualification-evidence/ecommerce-l3-7cd96d01b/spacetime-mutation.json","sha256":"d84ef17127281df87dad20fceb4efab78a33a59b374dceb206efb98e571fb1eb"}],"featureCatalog":{"path":"progression/ecommerce.json","contentSha256":"8671f7883c2e5a24474a546ef1517407cd9334258e1a7cfe91e292a9af1952f2","id":"ecommerce.questlines"}},"recipe":{"path":"composition/recipes/progression-catalog.json","id":"ecommerce.progression-catalog","meaningSha256":"9724c6dc245ca2cc7d19c9f17938c6edcf3a0234ffbf84b4a48bc8f627aa9337","executionSha256":"2a95cbdeb0deaca8fc6f07167df3c3dbd36541b845133ba34617fc88d54cbd85","contentSha256":"104589b973c1e7dd1a2410659759989eb0de08b16efeda3131777f82858a0a8b"},"references":{"entries":[{"backend":"mongodb","id":"ecommerce-reference-mongodb","sourceSha256":"0d21bbc4b2768f4077a81d676f0d4c87a65067dda8f2c5ffeb2fa9208381dc7e","targetPath":"reference-apps/ecommerce/mongodb"},{"backend":"postgres","id":"ecommerce-reference-postgres","sourceSha256":"f3906fa01050f00a0ed76c69c256a6b0013bbf72eb72c03aa92d79e47b71c2b8","targetPath":"reference-apps/ecommerce/postgres"},{"backend":"spacetime","id":"ecommerce-reference-spacetime","sourceSha256":"7ba1f548e89f461b95b5caf843b0fbcf2b81278428d02869d7f47e1a199eaf6e","targetPath":"reference-apps/ecommerce/spacetime"}],"registryPath":"reference-apps/registry.json"},"selection":{"alias":"L3","coveredAliases":["L1","L2","L3"],"path":"composition/dependency.json","sha256":"e73002df8a7a42e612f2bd1ee5de1f9db2d6c13cb9c819e405a5f2512eca3048"},"title":"Ecommerce dependency L3 calibration","track":"ecommerce"},"mutations":{"mongodb":{"schemaVersion":3,"fixtureSha256":"0d21bbc4b2768f4077a81d676f0d4c87a65067dda8f2c5ffeb2fa9208381dc7e","backend":"mongodb","track":"ecommerce","note":"Mutation definitions for the MongoDB ecommerce reference.","mutations":[{"id":"recommendation-dismissal-lost-on-restart","scenario":"tracks/ecommerce/scenarios/progression-recommendation-feedback.json","targets":["ecommerce.spec.state-durability.recommendation-feedback-restart.504c"],"desc":"Erase saved recommendation dismissals when the application starts again.","file":"server/src/index.ts","edits":[{"find":" await mongoose.connect(DATABASE_URL);","replace":" await mongoose.connect(DATABASE_URL);\n await Dismissal.deleteMany({});"}]},{"id":"pending-order-item-return-accepted","scenario":"tracks/ecommerce/scenarios/progression-order-return-boundary.json","targets":["ecommerce.returns-pricing.cancellation-and-return.3f"],"desc":"Accept a pending order return and restore its stock before shipment.","file":"server/src/index.ts","edits":[{"find":"if (!['shipped', 'delivered'].includes(value.status)) throw new Error('No shipped order found');","replace":"if (!['pending', 'shipped', 'delivered'].includes(value.status)) throw new Error('No shipped order found');"}]},{"id":"staff-admin-access-survives-role-removal","scenario":"tracks/ecommerce/scenarios/progression-staff-roles.json","targets":["ecommerce.spec.access-control.staff-role-revocation.621d"],"desc":"Keep administrator access after changing the assigned role back to staff.","file":"server/src/progression.ts","edits":[{"find":" target.isAdmin = role === \"admin\";","replace":" target.isAdmin = target.isAdmin || role === \"admin\";"}]},{"id":"shipping-counts-sale-twice","scenario":"tracks/ecommerce/scenarios/progression-shipping-accounting.json","targets":["ecommerce.inventory-operations.shipping-accounting.202e"],"desc":"Shipping succeeds but doubles the completed sale value in authoritative revenue.","file":"server/src/index.ts","edits":[{"find":" order.status = \"shipped\";\n await order.save();","replace":" order.status = \"shipped\";\n order.total *= 2;\n await order.save();"}]},{"id":"signup-does-not-expose-created-account","scenario":"tracks/ecommerce/scenarios/01-account-create.json","targets":["ecommerce.feature.accounts.accounts.1a"],"desc":"Signup succeeds but the client discards the created account identity from its current session view.","file":"client/src/App.tsx","edits":[{"find":" saveSession(data.token, data.user);\n };\n\n const handleSignIn","replace":" saveSession(data.token, { ...data.user, username: \"\" });\n };\n\n const handleSignIn"}]},{"id":"duplicate-signup-reports-success","scenario":"tracks/ecommerce/scenarios/01-account-duplicate.json","targets":["ecommerce.feature.accounts.accounts.1b"],"desc":"A duplicate username is reported as a successful empty signup response instead of a refusal.","file":"server/src/index.ts","edits":[{"find":" if (existing) return res.status(409).json({ error: \"Username is already taken\" });","replace":" if (existing) return res.json({}); // mutant: duplicate signup is falsely accepted"}]},{"id":"signin-skips-password-verification","scenario":"tracks/ecommerce/scenarios/01-account-password.json","targets":["ecommerce.feature.accounts.accounts.1c"],"desc":"Signin accepts an existing account without requiring its password to match.","file":"server/src/index.ts","edits":[{"find":" if (!valid) return res.status(401).json({ error: \"Invalid username or password\" });","replace":" if (false && !valid) return res.status(401).json({ error: \"Invalid username or password\" });"}]},{"id":"signout-keeps-current-account","scenario":"tracks/ecommerce/scenarios/01-account-signout.json","targets":["ecommerce.feature.accounts.accounts.1d"],"desc":"Signout disconnects the token state but leaves the current account and persisted credential in place.","file":"client/src/App.tsx","edits":[{"find":" const handleSignOut = () => {\n clearSession();\n };","replace":" const handleSignOut = () => {\n setToken(null); // mutant: visible and persisted account state is not cleared\n };"}]},{"id":"session-token-not-persisted","scenario":"tracks/ecommerce/scenarios/01-account-reload.json","targets":["ecommerce.spec.state-durability.session-reload.1e"],"desc":"The active session is kept only in React state and is unavailable after a page reload.","file":"client/src/App.tsx","edits":[{"find":" localStorage.setItem(TOKEN_KEY, tok);\n setToken(tok);","replace":" void tok; // mutant: the session token is never persisted\n setToken(tok);"}]},{"id":"purchase-counts-never-affect-ranking","scenario":"tracks/ecommerce/scenarios/01-core.json","targets":["ecommerce.spec.live-state.ranking.2c"],"desc":"The catalogue ranking ignores recorded purchases and therefore never promotes the bought item.","file":"server/src/index.ts","edits":[{"find":" purchaseCount: purchaseMap.get(id) || 0,","replace":" purchaseCount: 0, // mutant: ranking ignores durable purchase counts"}]},{"id":"signed-out-visitor-purchase-is-accepted","scenario":"tracks/ecommerce/scenarios/progression-signed-out-purchase.json","targets":["ecommerce.spec.access-control.signed-out-purchase.3a"],"desc":"The UI exposes purchase controls to visitors and the buy route assigns unauthenticated requests an unverified identity, allowing an actual stock-debiting order.","file":"client/src/App.tsx","edits":[{"find":" const isCustomer = !!currentUser && !currentUser.isAdmin && !currentUser.isStaff;","replace":" const isCustomer = !currentUser?.isAdmin && !currentUser?.isStaff;"},{"file":"server/src/index.ts","find":"app.post(\"/api/items/:id/buy\", requireAuth, async (req, res) => {","replace":"app.post(\"/api/items/:id/buy\", async (req, _res, next) => {\n (req as any).user = await userFromToken(extractToken(req)) || { _id: new Types.ObjectId() };\n next();\n}, async (req, res) => {"}]},{"id":"espresso-stock-row-ignores-live-updates","scenario":"tracks/ecommerce/scenarios/01-buying.json","targets":["ecommerce.spec.live-state.purchase-stock.3b"],"desc":"The live catalogue handler preserves a stale Espresso Machine stock projection while applying all other item updates.","file":"client/src/App.tsx","edits":[{"find":" socket.on(\"items:update\", (data: ItemT[]) => setItems(data));","replace":" socket.on(\"items:update\", (data: ItemT[]) => setItems((previous) => data.map((item) => item.name === \"Espresso Machine\" ? { ...item, stock: previous.find((old) => old.id === item.id)?.stock ?? item.stock } : item)));"}]},{"id":"restock-race-records-wrong-order-total","scenario":"tracks/ecommerce/scenarios/01-restock-race.json","targets":["ecommerce.spec.concurrency-safety.restock-race.202a"],"desc":"Purchases preserve stock and visible order counts but record the wrong booked total. Native mixed-race reconciliation must reject them.","file":"server/src/index.ts","edits":[{"find":" total: item.price,\n });","replace":" total: 0, // mutant: purchase receipt loses the authoritative price\n });"}]},{"id":"purchase-order-uses-zero-price","scenario":"tracks/ecommerce/scenarios/progression-purchasing.json","targets":["ecommerce.feature.purchasing.purchase-order.3c"],"desc":"A direct purchase records the item but stores a zero order total instead of the price paid.","file":"server/src/index.ts","edits":[{"find":" total: item.price,\n });","replace":" total: 0, // mutant: purchase receipt loses the authoritative price\n });"}]},{"id":"reload-hydrates-an-empty-cart","scenario":"tracks/ecommerce/scenarios/01-cart.json","targets":["ecommerce.spec.state-durability.cart-reload.4b"],"desc":"Cart hydration discards the persisted server response after reload.","file":"client/src/App.tsx","edits":[{"find":" const refreshCart = useCallback(async (tok: string) => {\n const data = await apiFetch(\"/api/cart\", tok);\n setCart(data);\n }, []);","replace":" const refreshCart = useCallback(async (tok: string) => {\n await apiFetch(\"/api/cart\", tok);\n setCart({ items: [], total: 0 }); // mutant: persisted cart response is discarded\n }, []);"}]},{"id":"shared-cart-live-events-ignored","scenario":"tracks/ecommerce/scenarios/01-cart.json","targets":["ecommerce.spec.live-state.shared-cart.4c"],"desc":"An already-open second session ignores committed cart update events.","file":"client/src/App.tsx","edits":[{"find":" socket.on(\"cart:update\", (data: CartT) => setCart(data));","replace":" socket.on(\"cart:update\", (data: CartT) => setCart(current => current.items.length === 0 ? current : data)); // mutant: an empty second-session cart ignores its first remote update"}]},{"id":"review-comment-is-not-persisted","scenario":"tracks/ecommerce/scenarios/01-review-visibility.json","targets":["ecommerce.feature.reviews.reviews.6a"],"desc":"Review submission persists an empty comment rather than the customer's submitted text.","file":"server/src/index.ts","edits":[{"find":" { itemId, userId: user._id, username: user.username, rating: ratingNum,\n comment: typeof comment === \"string\" ? comment : \"\" },","replace":" { itemId, userId: user._id, username: user.username, rating: ratingNum,\n comment: \"\" },"}]},{"id":"repeat-review-uses-a-new-owner-key","scenario":"tracks/ecommerce/scenarios/01-review-uniqueness.json","targets":["ecommerce.spec.transactional-integrity.unique-review.6b"],"desc":"Each review submission is stored under a fresh owner key, bypassing the one-review-per-customer constraint.","file":"server/src/index.ts","edits":[{"find":" { itemId, userId: user._id },\n { itemId, userId: user._id, username: user.username, rating: ratingNum,\n comment: typeof comment === \"string\" ? comment : \"\" },","replace":" { itemId, userId: new Types.ObjectId() },\n { itemId, userId: new Types.ObjectId(), username: user.username, rating: ratingNum,\n comment: typeof comment === \"string\" ? comment : \"\" },"}]},{"id":"live-review-average-uses-an-extra-divisor","scenario":"tracks/ecommerce/scenarios/01-review-rating-live.json","targets":["ecommerce.spec.live-state.rating.6c"],"desc":"The live review event divides the rating sum by one more review than actually exists.","file":"server/src/index.ts","edits":[{"find":"async function broadcastReviews(itemId: string) {\n const reviews = await Review.find({ itemId }).sort({ createdAt: -1 });\n const average = reviews.length ? reviews.reduce((s, r) => s + r.rating, 0) / reviews.length : 0;","replace":"async function broadcastReviews(itemId: string) {\n const reviews = await Review.find({ itemId }).sort({ createdAt: -1 });\n const average = reviews.length ? reviews.reduce((s, r) => s + r.rating, 0) / (reviews.length + 1) : 0;"}]},{"id":"warehouse-view-omits-one-location","scenario":"tracks/ecommerce/scenarios/01-warehouse-admin-staff.json","targets":["ecommerce.feature.warehouse-admin.warehouse-view.7b"],"desc":"The admin warehouse projection truncates the final item-location row.","file":"client/src/App.tsx","edits":[{"find":" {overview.locations.map((loc) => (","replace":" {overview.locations.slice(0, -1).map((loc) => ("}]},{"id":"unauthenticated-purchase-defaults-to-admin","scenario":"tracks/ecommerce/scenarios/01-purchase-session.json","targets":["ecommerce.spec.access-control.purchase-session.101a"],"desc":"The purchase endpoint drops authentication and assigns sessionless purchases to the seeded administrator.","file":"server/src/index.ts","edits":[{"find":"app.post(\"/api/items/:id/buy\", requireAuth, async (req, res) => {","replace":"app.post(\"/api/items/:id/buy\", async (req, res) => {"},{"find":" const user = (req as any).user;\n const order = await Order.create({","replace":" const user = (req as any).user || await User.findOne({ username: \"admin\" });\n const order = await Order.create({"}]},{"id":"direct-purchase-total-ignores-store-price","scenario":"tracks/ecommerce/scenarios/01-server-price.json","targets":["ecommerce.spec.transactional-integrity.server-price.104a"],"desc":"The direct purchase creates one order but records a zero total rather than the store's current price.","file":"server/src/index.ts","edits":[{"find":" total: item.price,\n });","replace":" total: 0, // mutant: direct purchase ignores the authoritative price\n });"}]},{"id":"cart-hydration-loses-account-state","scenario":"tracks/ecommerce/scenarios/progression-account-state-reload.json","targets":["ecommerce.spec.state-durability.account-state-recovery.105a"],"desc":"Reload hydration discards the account's persisted cart response.","file":"client/src/App.tsx","edits":[{"find":" const refreshCart = useCallback(async (tok: string) => {\n const data = await apiFetch(\"/api/cart\", tok);\n setCart(data);\n }, []);","replace":" const refreshCart = useCallback(async (tok: string) => {\n await apiFetch(\"/api/cart\", tok);\n setCart({ items: [], total: 0 }); // mutant: account state is discarded on hydration\n }, []);"}]},{"id":"reconnect-hydration-loses-account-state","scenario":"tracks/ecommerce/scenarios/progression-account-state-reconnect.json","targets":["ecommerce.spec.state-durability.account-state-recovery.105b"],"desc":"The initial account cart loads correctly, but after network restoration the client ignores both refreshed and pushed cart state.","file":"client/src/App.tsx","edits":[{"find":" useEffect(() => {\n const socket = io({ auth: token ? { token } : {} });","replace":" useEffect(() => {\n const clearAccountOffline = () => {\n setCurrentUser(null);\n setCart({ items: [], total: 0 });\n };\n window.addEventListener(\"offline\", clearAccountOffline, { once: true });\n const socket = io({ auth: token ? { token } : {} });"}]},{"id":"order-history-is-not-owner-scoped","scenario":"tracks/ecommerce/scenarios/01-order-ownership.json","targets":["ecommerce.spec.access-control.order-ownership.106a"],"desc":"Order history returns every customer's orders instead of filtering by the authenticated owner.","file":"server/src/index.ts","edits":[{"find":" const orders = await Order.find({ userId }).sort({ createdAt: -1 });","replace":" const orders = await Order.find({}).sort({ createdAt: -1 });"}]},{"id":"revenue-aggregation-ignores-order-totals","scenario":"tracks/ecommerce/scenarios/progression-books-balance.json","targets":["ecommerce.spec.transactional-integrity.books-balance.107a"],"desc":"The admin revenue aggregation counts every order as zero regardless of its stored total.","file":"server/src/index.ts","edits":[{"find":" { $group: { _id: null, total: { $sum: { $subtract: [\"$total\", { $ifNull: [\"$refundTotal\", 0] }] } } } },","replace":" { $group: { _id: null, total: { $sum: 0 } } },"}]},{"id":"unpurchased-review-is-accepted","scenario":"tracks/ecommerce/scenarios/01-review-eligibility.json","targets":["ecommerce.spec.access-control.review-eligibility.108a"],"desc":"The review endpoint bypasses its completed-purchase eligibility check.","file":"server/src/index.ts","edits":[{"find":" if (!hasPurchased) {\n return res.status(403).json({ error: \"You can only review items you have purchased\" });\n }","replace":" if (false && !hasPurchased) {\n return res.status(403).json({ error: \"You can only review items you have purchased\" });\n }"}]},{"id":"purchased-review-ui-does-not-submit","scenario":"tracks/ecommerce/scenarios/01-review-eligibility.json","targets":["ecommerce.spec.access-control.review-eligibility.108b"],"desc":"The review form discards valid customer submissions. Direct authorized and unauthorized review calls retain their normal behavior.","file":"client/src/App.tsx","edits":[{"find":" const handleReviewSubmit = async (itemId: string, rating: number, comment: string) => {\n setReviewError(\"\");","replace":" const handleReviewSubmit = async (itemId: string, rating: number, comment: string) => {\n setReviewError(\"Review submission unavailable\");\n return;"}]},{"id":"external-stock-polling-disabled","scenario":"tracks/ecommerce/scenarios/01-external-live-sync.json","targets":["ecommerce.spec.external-data-sync.external-stock.901a"],"desc":"The server stops reconciling direct database stock writes into live catalogue events.","file":"server/src/index.ts","edits":[{"find":" broadcastItems().catch((err) => console.error(\"broadcastItems poll failed\", err));","replace":" // mutant: direct database stock changes are never reconciled"}]},{"id":"server-restart-disables-catalog-recovery","scenario":"tracks/ecommerce/scenarios/01-external-server-restart-sync.json","targets":["ecommerce.spec.external-data-sync.external-stock.901c"],"desc":"After a socket disconnect, the existing page ignores both reconnect refreshes and later catalogue snapshots.","file":"client/src/App.tsx","edits":[{"find":" const socketRef = useRef(null);\n\n const saveSession","replace":" const socketRef = useRef(null);\n const acceptCatalogRecovery = useRef(true);\n\n const saveSession"},{"find":" socket.on(\"connect\", () => {\n refreshItems().catch((err) => console.error(err));","replace":" socket.on(\"disconnect\", () => { acceptCatalogRecovery.current = false; });\n socket.on(\"connect\", () => {\n if (acceptCatalogRecovery.current) refreshItems().catch((err) => console.error(err));"},{"find":" socket.on(\"items:update\", (data: ItemT[]) => setItems(data));","replace":" socket.on(\"items:update\", (data: ItemT[]) => { if (acceptCatalogRecovery.current) setItems(data); });"}]},{"id":"reconnect-generation-ignores-current-catalog","scenario":"tracks/ecommerce/scenarios/01-external-reconnect-sync.json","targets":["ecommerce.spec.external-data-sync.external-stock.901d"],"desc":"After the browser goes offline, the existing page ignores reconnect refreshes and subsequent catalogue events.","file":"client/src/App.tsx","edits":[{"find":" const socketRef = useRef(null);\n\n const saveSession","replace":" const socketRef = useRef(null);\n const acceptCatalogUpdates = useRef(true);\n useEffect(() => {\n const stopCatalogRecovery = () => { acceptCatalogUpdates.current = false; };\n window.addEventListener(\"offline\", stopCatalogRecovery);\n return () => window.removeEventListener(\"offline\", stopCatalogRecovery);\n }, []);\n\n const saveSession"},{"find":" setItems(data.items);","replace":" if (acceptCatalogUpdates.current) setItems(data.items);"},{"find":" socket.on(\"items:update\", (data: ItemT[]) => setItems(data));","replace":" socket.on(\"items:update\", (data: ItemT[]) => {\n if (acceptCatalogUpdates.current) setItems(data);\n });"}]},{"id":"open-review-list-ignores-live-update","scenario":"tracks/ecommerce/scenarios/progression-open-list-live.json","targets":["ecommerce.spec.live-state.open-list.902a"],"desc":"The already-open review list ignores a committed review update from another client.","file":"client/src/App.tsx","edits":[{"find":" setItemDetail((prev) => (prev && prev.id === payload.itemId ? { ...prev, reviews: payload.reviews, average: payload.average } : prev));","replace":" void payload; // mutant: the already-open review list ignores committed updates"}]},{"id":"cancel-does-not-restore-stock-feature","scenario":"tracks/ecommerce/scenarios/02-order-cancellation-core.json","targets":["ecommerce.returns-pricing.cancellation-and-return.3a"],"desc":"Cancellation changes order state but skips restoration of its recorded warehouse allocations.","file":"server/src/index.ts","edits":[{"find":" {item_id:line.itemId,warehouse_id:allocation.warehouseId}, {$inc:{quantity:allocation.quantity}}, {session});","replace":" {item_id:line.itemId,warehouse_id:allocation.warehouseId}, {$inc:{quantity:0}}, {session});"}]},{"id":"cancellation-accounting-loses-stock-restoration","scenario":"tracks/ecommerce/scenarios/02-invariants.json","targets":["ecommerce.returns-pricing.refund-accounting.203a"],"desc":"Cancellation removes revenue and changes order status, but loses the original warehouse stock restoration. The native refund-accounting assertion must detect this.","file":"server/src/index.ts","edits":[{"find":" {item_id:line.itemId,warehouse_id:allocation.warehouseId}, {$inc:{quantity:allocation.quantity}}, {session});","replace":" {item_id:line.itemId,warehouse_id:allocation.warehouseId}, {$inc:{quantity:0}}, {session});"}]},{"id":"cancel-does-not-restore-stock-fresh-client","scenario":"tracks/ecommerce/scenarios/02-self-contained.json","targets":["ecommerce.inventory-operations.stock-conservation.202b","ecommerce.inventory-operations.stock-conservation.202c"],"desc":"Cancellation changes order state but skips restoration, so a fresh client reads the persisted shortfall.","file":"server/src/index.ts","edits":[{"find":" {item_id:line.itemId,warehouse_id:allocation.warehouseId}, {$inc:{quantity:allocation.quantity}}, {session});","replace":" {item_id:line.itemId,warehouse_id:allocation.warehouseId}, {$inc:{quantity:0}}, {session});"}]},{"id":"cancel-restores-stock-but-keeps-pending-status","scenario":"tracks/ecommerce/scenarios/02-order-cancellation-history.json","targets":["ecommerce.returns-pricing.cancellation-and-return.3b"],"desc":"Cancellation restores allocations but writes pending back to order history.","file":"server/src/index.ts","edits":[{"find":" value.status = \"cancelled\";\n await value.save({session});","replace":" value.status = \"pending\";\n await value.save({session});"}]},{"id":"cancelled-order-remains-in-revenue-feature","scenario":"tracks/ecommerce/scenarios/02-order-cancellation-core.json","targets":["ecommerce.returns-pricing.cancellation-and-return.3a"],"desc":"Admin revenue includes cancelled orders even though cancellation otherwise succeeds.","file":"server/src/index.ts","edits":[{"find":"async function getRevenue(): Promise {\n const rows = await Order.aggregate([\n { $match: { status: { $ne: \"cancelled\" } } },","replace":"async function getRevenue(): Promise {\n const rows = await Order.aggregate([\n { $match: {} },"}]},{"id":"cancelled-order-remains-in-revenue-invariant","scenario":"tracks/ecommerce/scenarios/02-invariants.json","targets":["ecommerce.returns-pricing.refund-accounting.203a"],"desc":"Admin revenue includes cancelled orders even though cancellation otherwise succeeds.","file":"server/src/index.ts","edits":[{"find":"async function getRevenue(): Promise {\n const rows = await Order.aggregate([\n { $match: { status: { $ne: \"cancelled\" } } },","replace":"async function getRevenue(): Promise {\n const rows = await Order.aggregate([\n { $match: {} },"}]},{"id":"operator-authorization-allows-customer-transfer","scenario":"tracks/ecommerce/scenarios/02-strengthened.json","targets":["ecommerce.operations-access.operator-authorization.201a"],"desc":"The transfer route keeps authentication but drops its administrator role gate.","file":"server/src/index.ts","edits":[{"find":"app.post(\"/api/admin/transfer\", requireAuth, requireAdmin, async (req, res) => {","replace":"app.post(\"/api/admin/transfer\", requireAuth, async (req, res) => {"}]},{"id":"customer-can-ship-order-direct-1-1","scenario":"tracks/ecommerce/scenarios/02-server-actions.json","targets":["ecommerce.operations-access.operator-authorization.201c"],"desc":"The shipping route keeps authentication but drops its staff role gate.","file":"server/src/index.ts","edits":[{"find":"app.post(\"/api/fulfilment/ship\", requireAuth, requireStaff, async (req, res) => {","replace":"app.post(\"/api/fulfilment/ship\", requireAuth, async (req, res) => {"}]},{"id":"customer-can-cancel-foreign-order-1-1","scenario":"tracks/ecommerce/scenarios/02-server-actions.json","targets":["ecommerce.operations-access.order-owner.204a"],"desc":"Cancellation retains authentication and pending-state validation but drops order ownership.","file":"server/src/index.ts","edits":[{"find":" const value = orderId ? await Order.findOne({ _id: orderId, userId: user._id }).session(session) : null;\n if (!value) return null;\n if (value.status !== \"pending\") throw new Error(\"Order cannot be cancelled\");","replace":" const value = orderId ? await Order.findOne({ _id: orderId }).session(session) : null;\n if (!value) return null;\n if (value.status !== \"pending\") throw new Error(\"Order cannot be cancelled\");"}]},{"id":"queue-depth-lags-one-order","scenario":"tracks/ecommerce/scenarios/02-fulfilment-live.json","targets":["ecommerce.operations-access.fulfilment-queue.1a"],"desc":"The queue renders every order but its visible depth remains one behind.","file":"client/src/App.tsx","edits":[{"find":"Orders waiting: {queue.depth}","replace":"Orders waiting: {Math.max(0, queue.depth - 1)}"}]},{"id":"ship-acknowledges-without-changing-status","scenario":"tracks/ecommerce/scenarios/02-fulfilment-ship.json","targets":["ecommerce.operations-access.fulfilment-queue.1c"],"desc":"Shipping returns success but writes pending back to the order, leaving both live views unchanged.","file":"server/src/index.ts","edits":[{"find":" order.status = \"shipped\";\n await order.save();","replace":" order.status = \"pending\";\n await order.save();"}]},{"id":"customer-sees-fulfilment-navigation","scenario":"tracks/ecommerce/scenarios/02-features.json","targets":["ecommerce.operations-access.fulfilment-queue.1d"],"desc":"Expose the protected staff area to signed-in customers, including its navigation and content.","file":"client/src/App.tsx","edits":[{"find":" {(currentUser?.isStaff || currentUser?.isAdmin) && (\n ","replace":" setState((value: any) => ({ ...value, preference: { ...preference, order: !preference.order } }))} />"},{"find":"function SupportTicket({ ticket, user, orders, act }: any) {","replace":"function OrderNotificationToggle({ on, onToggle }: { on: boolean; onToggle: () => void }) {\n const [shown] = useState(on); // mutant: the toggle keeps the state loaded when the card opened\n return ;\n}\n\nfunction SupportTicket({ ticket, user, orders, act }: any) {"}]},{"id":"role-editor-snaps-back-to-stored-role","scenario":"tracks/ecommerce/scenarios/progression-staff-roles.json","targets":["ecommerce.progression.staff-roles.staff-roles.621c"],"desc":"Pressing Save persists the role but resets the dropdown to the role that was stored before the save, so the assignment is not visible until a reload.","file":"client/src/ProgressionPanel.tsx","edits":[{"find":" ","replace":" "}]},{"id":"queue-ignores-live-fulfilment-updates","scenario":"tracks/ecommerce/scenarios/02-fulfilment-live.json","targets":["ecommerce.spec.live-state.fulfilment-queue.1a"],"desc":"The open staff queue ignores live fulfilment events, so a new order appears only after a reload.","file":"client/src/App.tsx","edits":[{"find":" socket.on(\"fulfilment:update\", (data: FulfilmentQueueT) => setFulfilmentQueue(data));","replace":" socket.on(\"fulfilment:update\", (data: FulfilmentQueueT) => { void data; }); // mutant: the open staff queue ignores live fulfilment updates"}]},{"id":"low-stock-boundary-excludes-ten-live","scenario":"tracks/ecommerce/scenarios/02-low-stock.json","targets":["ecommerce.spec.live-state.inventory-dashboard.5a"],"desc":"The low-stock view uses a strict boundary, so an item that falls to exactly ten units never joins the list.","file":"server/src/index.ts","edits":[{"find":" .filter((it) => it.stock <= 10)","replace":" .filter((it) => it.stock < 10)"}]},{"id":"live-admin-updates-keep-stale-category-totals","scenario":"tracks/ecommerce/scenarios/02-operational-category-totals.json","targets":["ecommerce.spec.live-state.sales-dashboard.5b"],"desc":"Live admin updates keep the category totals loaded at page load, so a purchase does not move units or revenue until a reload.","file":"client/src/App.tsx","edits":[{"find":" socket.on(\"admin:update\", (data: AdminOverviewT) => setAdminOverview(data));","replace":" socket.on(\"admin:update\", (data: AdminOverviewT) => setAdminOverview((previous) => previous ? { ...data, categories: previous.categories } : data)); // mutant: live admin updates keep the category totals loaded at page load"}]},{"id":"overdraw-transfer-is-accepted","scenario":"tracks/ecommerce/scenarios/02-transfer-overdraw.json","targets":["ecommerce.spec.transactional-integrity.stock-transfer-overdraw.2c"],"desc":"The atomic source debit no longer requires sufficient quantity, so an overdrawn transfer succeeds and moves both warehouse totals.","file":"server/src/index.ts","edits":[{"find":"{ item_id: itemId, warehouse_id: fromWarehouseId, quantity: { $gte: qty } }","replace":"{ item_id: itemId, warehouse_id: fromWarehouseId }"}]},{"id":"transfer-totals-omit-destination-credit-live","scenario":"tracks/ecommerce/scenarios/02-transfer-totals.json","targets":["ecommerce.spec.live-state.stock-transfers.2b"],"desc":"A transfer debits the source but adds zero to the destination, so the two live warehouse totals do not move in opposite directions.","file":"server/src/index.ts","edits":[{"find":" await Stock.findOneAndUpdate(\n { item_id: itemId, warehouse_id: toWarehouseId },\n { $inc: { quantity: qty } },\n { upsert: true }\n );","replace":" await Stock.findOneAndUpdate(\n { item_id: itemId, warehouse_id: toWarehouseId },\n { $inc: { quantity: 0 } },\n { upsert: true }\n );"}]},{"id":"credit-checkout-ignores-wallet","desc":"A credit checkout pays entirely externally despite available credit.","scenario":"tracks/ecommerce/scenarios/progression-store-credit.json","targets":["ecommerce.feature.store-credit.store-credit-750.750a"],"file":"server/src/credit.ts","edits":[{"find":" const creditMinor = useCredit ? Math.min(user.creditMinor, totalMinor) : 0;","replace":" const creditMinor = 0;"}]},{"id":"credit-grant-replay-increments-balance","desc":"Replaying a grant applies its credit to the wallet again.","scenario":"tracks/ecommerce/scenarios/progression-store-credit.json","targets":["ecommerce.spec.store-credit.production-752.752a"],"file":"server/src/credit.ts","edits":[{"find":" if (existing.amountMinor !== amountMinor) throw new Error('Reference already identifies another grant');\n return;","replace":" if (existing.amountMinor !== amountMinor) throw new Error('Reference already identifies another grant');\n await User.updateOne({ _id: accountId }, { $inc: { creditMinor: amountMinor } }, { session });\n return;"}]},{"id":"customer-can-grant-credit","desc":"Customer authentication is accepted without staff authorization.","scenario":"tracks/ecommerce/scenarios/progression-store-credit.json","targets":["ecommerce.spec.store-credit.production-753.753a"],"file":"server/src/credit.ts","edits":[{"find":" app.post('/api/staff/credit', auth, staff, async (req, res) => {","replace":" app.post('/api/staff/credit', auth, async (req, res) => {"}]},{"id":"credit-checkout-retains-purchased-cart","desc":"A second checkout can reuse the purchased cart and create another order.","scenario":"tracks/ecommerce/scenarios/progression-store-credit.json","targets":["ecommerce.spec.store-credit.production-754.754a"],"file":"server/src/credit.ts","edits":[{"find":" cart.items = cart.items.filter(line => line.reservationExpiresAt && line.reservationExpiresAt <= now) as any;","replace":" // mutant: purchased cart lines remain"}]},{"id":"split-refund-does-not-restore-credit","desc":"The refund is recorded but its original wallet credit is not restored.","scenario":"tracks/ecommerce/scenarios/progression-split-tender-refunds.json","targets":["ecommerce.feature.split-tender-refunds.split-tender-refunds-751.751a"],"file":"server/src/progression.ts","edits":[{"find":" await refundCredit(order, session);","replace":" // mutant: omit wallet restoration"}]},{"id":"split-refund-duplicates-credit","desc":"A refund credits the wallet twice while recording one refund.","scenario":"tracks/ecommerce/scenarios/progression-split-tender-refunds.json","targets":["ecommerce.spec.split-tender-refunds.production-756.756a"],"file":"server/src/credit.ts","edits":[{"find":"{ $inc: { creditMinor: delta } }, { session });","replace":"{ $inc: { creditMinor: delta * 2 } }, { session });"}]},{"id":"subscription-skips-due-purchase","desc":"Due deliveries are recorded as skipped although stock is available.","scenario":"tracks/ecommerce/scenarios/progression-subscriptions.json","targets":["ecommerce.feature.subscriptions.subscriptions-760.760a"],"file":"server/src/subscriptions.ts","edits":[{"find":" const allocation = await reserveStock(row.itemId, row.quantity, session);","replace":" const allocation = row.quantity < 0 ? await reserveStock(row.itemId, row.quantity, session) : null;"}]},{"id":"subscription-allows-foreign-cancellation","desc":"A customer can cancel another customer subscription.","scenario":"tracks/ecommerce/scenarios/progression-subscriptions.json","targets":["ecommerce.spec.subscriptions.production-762.762a"],"file":"server/src/subscriptions.ts","edits":[{"find":" if (!row || String(row.userId) !== String((req as any).user._id)) return false;","replace":" if (!row) return false;"}]},{"id":"subscription-pause-is-not-recorded","desc":"Pause acknowledges the request but the subscription remains active.","scenario":"tracks/ecommerce/scenarios/progression-subscriptions.json","targets":["ecommerce.spec.subscriptions.production-763.763a"],"file":"server/src/subscriptions.ts","edits":[{"find":" row.status = 'paused'; row.pausedAt = new Date();","replace":" row.status = 'active'; row.pausedAt = new Date();"}]},{"id":"credit-balance-is-cleared-at-startup","desc":"Restart clears an issued wallet balance while leaving accounts present.","file":"server/src/index.ts","scenario":"tracks/ecommerce/scenarios/progression-store-credit.json","targets":["ecommerce.spec.store-credit.production-755.755a"],"edits":[{"find":" await seed();","replace":" await seed();\n await User.updateMany({}, { $set: { creditMinor: 0 } });"}]},{"id":"pending-subscriptions-are-cleared-at-startup","desc":"Restart erases pending subscription work while preserving ordinary timer execution.","file":"server/src/index.ts","scenario":"tracks/ecommerce/scenarios/progression-subscriptions.json","targets":["ecommerce.spec.subscriptions.production-761.761a"],"edits":[{"find":" await seed();","replace":" await seed();\n await mongoose.connection.collection(\"purchasesubscriptions\").deleteMany({ status: \"active\" });"}]},{"id":"bundle-definition-loses-component-quantity","scenario":"tracks/ecommerce/scenarios/progression-product-bundles.json","targets":["ecommerce.feature.product-bundles.product-bundles.740a"],"desc":"definition loses component quantity","file":"server/src/bundles.ts","edits":[{"find":"quantity: component.quantity });","replace":"quantity: 1 });"}]},{"id":"bundle-catalog-write-allows-customers","scenario":"tracks/ecommerce/scenarios/progression-product-bundles.json","targets":["ecommerce.spec.bundle-integrity.bundle-743.743a"],"desc":"catalog write allows customers","file":"server/src/bundles.ts","edits":[{"find":"if (!actor.isAdmin && !actor.roles?.includes('catalog'))","replace":"if (false)"}]},{"id":"bundle-checkout-price-not-snapshot","scenario":"tracks/ecommerce/scenarios/progression-bundle-checkout.json","targets":["ecommerce.feature.bundle-checkout.bundle-checkout.741a"],"desc":"checkout price not snapshot","file":"server/src/bundles.ts","edits":[{"find":"bundlePrice: bundle.price,","replace":"bundlePrice: bundle.price + 1,"}]},{"id":"bundle-expiry-does-not-release-components","scenario":"tracks/ecommerce/scenarios/progression-bundle-checkout.json","targets":["ecommerce.spec.bundle-integrity.bundle-746.746a"],"desc":"expiry does not release components","file":"server/src/bundles.ts","edits":[{"find":"await releaseBundle(line.componentAllocations as Allocation[], session);\n line.componentAllocations = [] as any;","replace":"line.componentAllocations = [] as any; // mutant: component holds leak"}]},{"id":"bundle-return-loses-original-components","scenario":"tracks/ecommerce/scenarios/progression-bundle-returns.json","targets":["ecommerce.feature.bundle-returns.bundle-returns.742a"],"desc":"return loses original components","file":"server/src/bundles.ts","edits":[{"find":"for (const line of bundles) { await releaseBundle(line.componentAllocations as Allocation[], session); line.returned = true; }","replace":"for (const line of bundles) { line.returned = true; }"}]},{"id":"bundle-return-replay-restocks-again","scenario":"tracks/ecommerce/scenarios/progression-bundle-returns.json","targets":["ecommerce.spec.bundle-integrity.bundle-742.742b"],"desc":"return replay restocks again","file":"server/src/bundles.ts","edits":[{"find":"line.isBundle && !line.returned","replace":"line.isBundle"}]},{"id":"bundle-return-crosses-account-boundary","scenario":"tracks/ecommerce/scenarios/progression-bundle-returns.json","targets":["ecommerce.spec.bundle-integrity.bundle-748.748a"],"desc":"return crosses account boundary","file":"server/src/bundles.ts","edits":[{"find":"{ _id: req.params.orderId, userId, status: { $in: ['shipped', 'delivered'] } }","replace":"{ _id: req.params.orderId, status: { $in: ['shipped', 'delivered'] } }"}]},{"id":"bundle-components-can-overdraw","scenario":"tracks/ecommerce/scenarios/progression-bundle-checkout.json","targets":["ecommerce.spec.bundle-integrity.bundle-744.744a","ecommerce.spec.bundle-integrity.bundle-745.745a"],"desc":"components can overdraw","file":"server/src/stock-reservations.ts","edits":[{"find":"{ item_id: itemId, quantity: { $gte: 1 } }","replace":"{ item_id: itemId }"}]},{"id":"bundle-checkout-reuses-reservation","scenario":"tracks/ecommerce/scenarios/progression-bundle-checkout.json","targets":["ecommerce.spec.bundle-integrity.bundle-747.747a"],"desc":"checkout reuses reservation","file":"server/src/credit.ts","edits":[{"find":"cart.items = cart.items.filter(line => line.reservationExpiresAt && line.reservationExpiresAt <= now) as any;","replace":"// mutant: active cart survives checkout"}]},{"id":"return-after-support-refund-is-blocked","scenario":"tracks/ecommerce/scenarios/progression-support-return-interaction.json","targets":["ecommerce.feature.split-tender-refunds.return-refund-interaction.757a"],"desc":"Reject a valid physical return after a financial refund.","file":"server/src/index.ts","edits":[{"find":" if (!line || line.returned) throw new Error('No returnable item found');","replace":" if (!line || line.returned || value.refundTotal > 0) throw new Error('No returnable item found');"}]},{"id":"support-refund-after-return-pays-twice","scenario":"tracks/ecommerce/scenarios/progression-support-return-interaction.json","targets":["ecommerce.feature.split-tender-refunds.return-refund-interaction.757b"],"desc":"Pay the full order again after a physical return.","file":"server/src/progression.ts","edits":[{"find":" order.refundTotal = order.total;","replace":" order.refundTotal += order.total;"}]},{"id":"support-history-leaks-to-signed-out-visitors","scenario":"tracks/ecommerce/scenarios/progression-support-history.json","targets":["ecommerce.spec.access-control.support-history-logout.612d"],"desc":"Disclose support tickets to signed-out visitors while leaving signed-in ownership filtering unchanged.","file":"server/src/progression.ts","edits":[{"find":"const ticketFilter = isStaff ? {} : user ? { userId: user._id } : { _id: null };","replace":"const ticketFilter = isStaff ? {} : user ? { userId: user._id } : {};"}]},{"id":"checkout-crash-integrity","scenario":"tracks/ecommerce/scenarios/progression-checkout-crash.json","targets":["ecommerce.spec.state-durability.checkout-crash-integrity.910a"],"desc":"A lifecycle callback changes a prepared or cleared cart to quantity two, leaving neither a legal rollback nor a complete checkout.","file":"server/src/index.ts","edits":[{"find":" await initializeOrderData(mongoose.connection);","replace":" await initializeOrderData(mongoose.connection);\n for (const cart of await Cart.find()) { const order = await Order.findOne({ userId: cart.userId }); if (order?.items[0]) await Cart.updateOne({ _id: cart._id }, { $set: { items: [{ itemId: order.items[0].itemId, quantity: 2 }] } }); }"}]},{"id":"checkout-crash-durability","scenario":"tracks/ecommerce/scenarios/progression-checkout-crash.json","targets":["ecommerce.spec.state-durability.checkout-crash-durability.910b"],"desc":"A lifecycle callback corrupts earlier order totals. The unchanged prepared snapshots and acknowledged baseline must expose the damage.","file":"server/src/index.ts","edits":[{"find":" await initializeOrderData(mongoose.connection);","replace":" await initializeOrderData(mongoose.connection);\n await Order.updateMany({}, { $set: { total: 0 } });"}]},{"id":"review-script-unsafe-render","scenario":"tracks/ecommerce/scenarios/progression-review-script.json","targets":["ecommerce.progression.review-access-specifications.stored-review-script.9180a"],"desc":"Render stored review text as HTML so it executes in another customer session.","file":"client/src/App.tsx","edits":[{"find":"
{r.comment}
","replace":"
"}]},{"id":"review-script-reject-all","scenario":"tracks/ecommerce/scenarios/progression-review-script.json","targets":["ecommerce.progression.review-access-specifications.stored-review-script.9180a"],"desc":"Reject all nonempty reviews, including the required benign review; absence of script is insufficient.","file":"server/src/index.ts","edits":[{"find":"const { rating, comment } = req.body || {};","replace":"const { rating, comment } = req.body || {};\n if (String(comment).length > 0) { res.status(400).json({ error: \"Review rejected\" }); return; }"}]}]},"postgres":{"schemaVersion":3,"fixtureSha256":"f3906fa01050f00a0ed76c69c256a6b0013bbf72eb72c03aa92d79e47b71c2b8","backend":"postgres","track":"ecommerce","note":"Mutation definitions for the PostgreSQL ecommerce reference.","mutations":[{"id":"recommendation-dismissal-lost-on-restart","scenario":"tracks/ecommerce/scenarios/progression-recommendation-feedback.json","targets":["ecommerce.spec.state-durability.recommendation-feedback-restart.504c"],"desc":"Erase saved recommendation dismissals when the application starts again.","file":"server/src/index.ts","edits":[{"find":" await initializeProgressionSchema(pool);","replace":" await initializeProgressionSchema(pool);\n await pool.query('DELETE FROM recommendation_dismissal');"}]},{"id":"pending-order-item-return-accepted","scenario":"tracks/ecommerce/scenarios/progression-order-return-boundary.json","targets":["ecommerce.returns-pricing.cancellation-and-return.3f"],"desc":"Accept a pending order return and restore its stock before shipment.","file":"server/src/index.ts","edits":[{"find":"if (!['shipped', 'delivered'].includes(orderRow.rows[0].status)) {","replace":"if (!['pending', 'shipped', 'delivered'].includes(orderRow.rows[0].status)) {"}]},{"id":"staff-admin-access-survives-role-removal","scenario":"tracks/ecommerce/scenarios/progression-staff-roles.json","targets":["ecommerce.spec.access-control.staff-role-revocation.621d"],"desc":"Keep administrator access after changing the assigned role back to staff.","file":"server/src/progression.ts","edits":[{"find":"is_admin = ($1 = 'admin')","replace":"is_admin = (is_admin OR $1 = 'admin')"}]},{"id":"shipping-counts-sale-twice","scenario":"tracks/ecommerce/scenarios/progression-shipping-accounting.json","targets":["ecommerce.inventory-operations.shipping-accounting.202e"],"desc":"Shipping succeeds but doubles the completed sale value in authoritative revenue.","file":"server/src/index.ts","edits":[{"find":"`UPDATE orders SET status = 'shipped', shipped_at = now()\n WHERE id = $1 AND status = 'pending' RETURNING account_id`","replace":"`UPDATE orders SET status = 'shipped', shipped_at = now(), total = total * 2\n WHERE id = $1 AND status = 'pending' RETURNING account_id`"}]},{"id":"signup-ui-does-not-enter-created-account","scenario":"tracks/ecommerce/scenarios/01-account-create.json","targets":["ecommerce.feature.accounts.accounts.1a"],"desc":"Create the account successfully but discard the returned signed-in identity in the client.","file":"client/src/App.tsx","edits":[{"find":" const r = await api<{ account: Account }>(\"/api/auth/signup\", {\n method: \"POST\",\n body: JSON.stringify({ username, password }),\n });\n setAccount(r.account);","replace":" const r = await api<{ account: Account }>(\"/api/auth/signup\", {\n method: \"POST\",\n body: JSON.stringify({ username, password }),\n });\n void r;\n setAccount(null);"}]},{"id":"duplicate-signup-authenticates-existing-account","scenario":"tracks/ecommerce/scenarios/01-account-duplicate.json","targets":["ecommerce.feature.accounts.accounts.1b"],"desc":"Treat a duplicate signup as a successful session for the pre-existing account.","file":"server/src/index.ts","edits":[{"find":" if (existing.length > 0) {\n res.status(409).json({ error: \"username already taken\" });\n return;\n }","replace":" if (existing.length > 0) {\n const token = newToken();\n await db.insert(session).values({ id: token, accountId: existing[0].id });\n res.cookie(\"sid\", token, { httpOnly: true, sameSite: \"lax\", path: \"/\" });\n res.json({ account: { id: existing[0].id, username, isAdmin: false, isStaff: false } });\n return;\n }"}]},{"id":"password-verification-is-inverted","scenario":"tracks/ecommerce/scenarios/01-account-password.json","targets":["ecommerce.feature.accounts.accounts.1c"],"desc":"Accept a wrong password instead of enforcing password verification.","file":"server/src/index.ts","edits":[{"find":" if (rows.length === 0 || !verifyPassword(password, rows[0].passwordHash)) {","replace":" if (rows.length === 0 || verifyPassword(password, rows[0].passwordHash)) {"}]},{"id":"correct-signin-is-refused","scenario":"tracks/ecommerce/scenarios/01-account-signout.json","targets":["ecommerce.feature.accounts.accounts.1d"],"desc":"Preserve wrong-password refusal but reject an otherwise valid sign-in, preventing a signed-out account from returning.","file":"server/src/index.ts","edits":[{"find":" const acc = rows[0];\n const token = newToken();","replace":" const acc = rows[0];\n if (username === acc.username) {\n res.status(401).json({ error: \"sign in is unavailable\" });\n return;\n }\n const token = newToken();"}]},{"id":"reload-discards-session-identity","scenario":"tracks/ecommerce/scenarios/01-account-reload.json","targets":["ecommerce.spec.state-durability.session-reload.1e"],"desc":"Ignore the authenticated identity returned during initial page hydration.","file":"client/src/App.tsx","edits":[{"find":" setAccount(me.account);","replace":" setAccount(null);"}]},{"id":"purchase-does-not-broadcast-ranking","scenario":"tracks/ecommerce/scenarios/01-core.json","targets":["ecommerce.spec.live-state.ranking.2c"],"desc":"Commit the purchase but omit the catalog broadcast that updates already-open rankings.","file":"server/src/index.ts","edits":[{"find":" lastCatalogJson = json;\n io.emit(\"items:update\", { items: catalog });","replace":" lastCatalogJson = json;\n // mutant: changed catalog state is not broadcast"}]},{"id":"signed-out-purchase-uses-default-account","scenario":"tracks/ecommerce/scenarios/progression-signed-out-purchase.json","targets":["ecommerce.spec.access-control.signed-out-purchase.3a"],"desc":"Expose purchase controls to guests and let the purchase route charge the first stored account when no caller is authenticated.","file":"client/src/App.tsx","edits":[{"find":" const canBuy = !!account && !account.isAdmin && !account.isStaff;","replace":" const canBuy = !account || (!account.isAdmin && !account.isStaff);"},{"file":"server/src/index.ts","find":" \"/api/items/:id/buy\",\n requireAuth,\n asyncHandler(async (req, res) => {\n const itemId = Number(req.params.id);\n const accountId = req.account!.id;","replace":" \"/api/items/:id/buy\",\n asyncHandler(async (req, res) => {\n const itemId = Number(req.params.id);\n const accountId = req.account?.id ?? (await pool.query(`SELECT id FROM account ORDER BY id LIMIT 1`)).rows[0].id;"}]},{"id":"purchase-stock-change-is-not-broadcast--01-buying","scenario":"tracks/ecommerce/scenarios/01-buying.json","targets":["ecommerce.spec.live-state.purchase-stock.3b"],"desc":"Commit purchases without broadcasting their stock changes, breaking live stock and sold-out visibility.","file":"server/src/index.ts","edits":[{"find":" lastCatalogJson = json;\n io.emit(\"items:update\", { items: catalog });","replace":" lastCatalogJson = json;\n // mutant: changed stock is not broadcast"}]},{"id":"purchase-stock-change-is-not-broadcast--stock-limit","scenario":"tracks/ecommerce/scenarios/progression-stock-limit.json","targets":["ecommerce.spec.concurrency-safety.stock-limit.3d"],"desc":"Commit purchases without broadcasting their stock changes, breaking live stock and sold-out visibility.","file":"server/src/index.ts","edits":[{"find":" lastCatalogJson = json;\n io.emit(\"items:update\", { items: catalog });","replace":" lastCatalogJson = json;\n // mutant: changed stock is not broadcast"}]},{"id":"restock-race-records-wrong-order-total","scenario":"tracks/ecommerce/scenarios/01-restock-race.json","targets":["ecommerce.spec.concurrency-safety.restock-race.202a"],"desc":"Purchases preserve stock and visible order counts but record the wrong booked total. Native mixed-race reconciliation must reject them.","file":"server/src/index.ts","edits":[{"find":" [accountId, price]\n );","replace":" [accountId, Number(price) + 1]\n );"}]},{"id":"direct-purchase-order-total-is-offset","scenario":"tracks/ecommerce/scenarios/progression-purchasing.json","targets":["ecommerce.feature.purchasing.purchase-order.3c"],"desc":"Record a direct purchase one dollar above the stored price.","file":"server/src/index.ts","edits":[{"find":" [accountId, price]\n );","replace":" [accountId, Number(price) + 1]\n );"}]},{"id":"reload-hydrates-an-empty-cart","scenario":"tracks/ecommerce/scenarios/01-cart.json","targets":["ecommerce.spec.state-durability.cart-reload.4b"],"desc":"Return an empty cart from both reload hydration paths while preserving later live cart broadcasts.","file":"server/src/index.ts","edits":[{"find":" const state = await buildCartState(req.account!.id);\n res.json(state);","replace":" await buildCartState(req.account!.id);\n res.json({ items: [], total: 0 });"},{"find":" const cartState = await buildCartState(acc.id);\n socket.emit(\"cart:update\", cartState);","replace":" await buildCartState(acc.id);\n socket.emit(\"cart:update\", { items: [], total: 0 });"}]},{"id":"signed-out-visitors-do-not-see-reviews","scenario":"tracks/ecommerce/scenarios/01-review-visibility.json","targets":["ecommerce.feature.reviews.reviews.6a"],"desc":"Hide an item's reviews whenever the viewer is signed out.","file":"client/src/App.tsx","edits":[{"find":" {reviews.length === 0 ? (","replace":" {!account || reviews.length === 0 ? ("}]},{"id":"review-average-update-is-not-broadcast","scenario":"tracks/ecommerce/scenarios/01-review-rating-live.json","targets":["ecommerce.spec.live-state.rating.6c"],"desc":"Return the new average to the submitter but omit the live review update to other viewers.","file":"server/src/index.ts","edits":[{"find":" io.emit(\"review:update\", { itemId, reviews, average });","replace":" // mutant: other open review views do not receive the new average"}]},{"id":"admin-warehouse-view-drops-one-location","scenario":"tracks/ecommerce/scenarios/01-warehouse-admin-staff.json","targets":["ecommerce.feature.warehouse-admin.warehouse-view.7b"],"desc":"Render only 23 of the 24 item-by-warehouse stock locations.","file":"client/src/App.tsx","edits":[{"find":" {admin.locations.map((loc) => {","replace":" {admin.locations.slice(0, 23).map((loc) => {"}]},{"id":"unauthenticated-direct-purchase-uses-default-account","scenario":"tracks/ecommerce/scenarios/01-purchase-session.json","targets":["ecommerce.spec.access-control.purchase-session.101a"],"desc":"Remove purchase authentication and attribute unauthenticated requests to a default account.","file":"server/src/index.ts","edits":[{"find":" \"/api/items/:id/buy\",\n requireAuth,","replace":" \"/api/items/:id/buy\","},{"find":" const itemId = Number(req.params.id);\n const accountId = req.account!.id;\n\n const client = await pool.connect();","replace":" const itemId = Number(req.params.id);\n const accountId = req.account?.id ?? 1;\n\n const client = await pool.connect();"}]},{"id":"direct-purchase-is-attributed-to-previous-account","scenario":"tracks/ecommerce/scenarios/01-purchase-attribution.json","targets":["ecommerce.spec.access-control.purchase-attribution.102a"],"desc":"Create the direct-purchase order for the preceding account id rather than the authenticated caller.","file":"server/src/index.ts","edits":[{"find":" const itemId = Number(req.params.id);\n const accountId = req.account!.id;\n\n const client = await pool.connect();","replace":" const itemId = Number(req.params.id);\n const accountId = req.account!.id - 1;\n\n const client = await pool.connect();"}]},{"id":"direct-purchase-uses-constant-price","scenario":"tracks/ecommerce/scenarios/01-server-price.json","targets":["ecommerce.spec.transactional-integrity.server-price.104a"],"desc":"Create a direct-purchase order at a hard-coded price instead of the current stored price.","file":"server/src/index.ts","edits":[{"find":" [accountId, price]\n );","replace":" [accountId, \"1.00\"]\n );"}]},{"id":"account-state-reload-discards-session","scenario":"tracks/ecommerce/scenarios/progression-account-state-reload.json","targets":["ecommerce.spec.state-durability.account-state-recovery.105a"],"desc":"Discard the authenticated account during reload hydration, making its cart and orders unavailable.","file":"client/src/App.tsx","edits":[{"find":" setAccount(me.account);","replace":" setAccount(null);"}]},{"id":"offline-event-clears-account-state","scenario":"tracks/ecommerce/scenarios/progression-account-state-reconnect.json","targets":["ecommerce.spec.state-durability.account-state-recovery.105b"],"desc":"Treat a temporary offline event as a sign-out and clear the account and cart state.","file":"client/src/App.tsx","edits":[{"find":" useEffect(() => {\n const socket = io({ path: \"/socket.io\" });","replace":" useEffect(() => {\n const clearAccountOffline = () => {\n setAccount(null);\n setCart({ items: [], total: 0 });\n };\n window.addEventListener(\"offline\", clearAccountOffline, { once: true });\n const socket = io({ path: \"/socket.io\" });"}]},{"id":"purchase-does-not-decrement-warehouse-stock","scenario":"tracks/ecommerce/scenarios/progression-books-balance.json","targets":["ecommerce.spec.transactional-integrity.books-balance.107b"],"desc":"Create purchase orders without decrementing their selected warehouse stock row.","file":"server/src/index.ts","edits":[{"find":" UPDATE stock s SET quantity = quantity - 1\n FROM target t","replace":" UPDATE stock s SET quantity = quantity\n FROM target t"}]},{"id":"review-route-skips-purchase-eligibility","scenario":"tracks/ecommerce/scenarios/01-review-eligibility.json","targets":["ecommerce.spec.access-control.review-eligibility.108a"],"desc":"Allow review creation even when the caller has never purchased the item.","file":"server/src/index.ts","edits":[{"find":" if (purchased.rowCount === 0) {","replace":" if (false && purchased.rowCount === 0) {"}]},{"id":"only-shipped-orders-earn-review-eligibility","scenario":"tracks/ecommerce/scenarios/01-review-eligibility.json","targets":["ecommerce.spec.access-control.review-eligibility.108b","ecommerce.spec.access-control.review-eligibility.108a"],"desc":"Incorrectly require an order to be shipped before its buyer may review the item. The same restriction also rejects the required successful buyer control in 108a; it does not independently test non-buyer denial.","file":"server/src/index.ts","edits":[{"find":" WHERE o.account_id = $1 AND oi.item_id = $2 LIMIT 1`,","replace":" WHERE o.account_id = $1 AND oi.item_id = $2 AND o.status = 'shipped' LIMIT 1`,"}]},{"id":"cart-update-accepts-negative-quantity","scenario":"tracks/ecommerce/scenarios/01-cart-boundary.json","targets":["ecommerce.spec.access-control.cart-boundary.109b"],"desc":"Accept a negative cart quantity update and persist it instead of refusing the named action.","file":"server/src/index.ts","edits":[{"find":" if (!Number.isInteger(quantity) || quantity < 1) {","replace":" if (!Number.isInteger(quantity)) {"}]},{"id":"oversell-no-row-lock","scenario":"tracks/ecommerce/scenarios/01-last-unit.json","targets":["ecommerce.spec.concurrency-safety.last-unit.201a","ecommerce.spec.concurrency-safety.last-unit.201b","ecommerce.spec.concurrency-safety.last-unit.201c"],"desc":"Drop the row lock so simultaneous buyers can select the same remaining units.","file":"server/src/index.ts","edits":[{"find":" FOR UPDATE\n LIMIT 1","replace":" LIMIT 1"}]},{"id":"purchase-read-write-loses-concurrent-stock","scenario":"tracks/ecommerce/scenarios/01-restock-race.json","targets":["ecommerce.spec.concurrency-safety.restock-race.202a"],"desc":"Replace atomic stock reservation with an unlocked read and absolute write. A fixed pause widens scheduling overlap; serial purchases and restocks retain their stock effects. Concurrent reservations or restocking can lose updates.","file":"server/src/index.ts","edits":[{"find":" const decrement = await client.query(\n `WITH target AS (\n SELECT item_id, warehouse_id FROM stock\n WHERE item_id = $1 AND quantity > 0\n ORDER BY warehouse_id\n FOR UPDATE\n LIMIT 1\n )\n UPDATE stock s SET quantity = quantity - 1\n FROM target t\n WHERE s.item_id = t.item_id AND s.warehouse_id = t.warehouse_id\n RETURNING s.item_id, s.warehouse_id`,\n [itemId]\n );\n","replace":" const snapshot = await client.query(\n `SELECT item_id, warehouse_id, quantity FROM stock\n WHERE item_id = $1 AND quantity > 0 ORDER BY warehouse_id LIMIT 1`, [itemId]\n );\n // Mutant: widen the unlocked read/write window without changing serial behavior.\n await new Promise(resolve => setTimeout(resolve, 500));\n const decrement = snapshot.rowCount === 0 ? snapshot : await client.query(\n `UPDATE stock SET quantity = $3 WHERE item_id = $1 AND warehouse_id = $2\n RETURNING item_id, warehouse_id`,\n [itemId, snapshot.rows[0].warehouse_id, snapshot.rows[0].quantity - 1]\n );\n"}]},{"id":"external-stock-polling-disabled","scenario":"tracks/ecommerce/scenarios/01-external-live-sync.json","targets":["ecommerce.spec.external-data-sync.external-stock.901a"],"desc":"Stop reconciling direct database changes while the server remains online.","file":"server/src/index.ts","edits":[{"find":" broadcastCatalog().catch((err) => console.error(\"poll broadcast failed\", err));","replace":" // mutant: direct database catalog changes are never reconciled"}]},{"id":"server-restart-does-not-resynchronize-catalog","scenario":"tracks/ecommerce/scenarios/01-external-server-restart-sync.json","targets":["ecommerce.spec.external-data-sync.external-stock.901c"],"desc":"After a server restart, omit both connection-time catalog hydration and periodic authoritative reconciliation.","file":"server/src/index.ts","edits":[{"find":" const catalog = await buildCatalog();\n socket.emit(\"items:update\", { items: catalog });","replace":" // mutant: reconnecting clients retain their pre-restart catalog"},{"find":" broadcastCatalog().catch((err) => console.error(\"poll broadcast failed\", err));","replace":" // mutant: restart recovery does not reconcile authoritative catalog state"}]},{"id":"reconnect-does-not-send-current-catalog","scenario":"tracks/ecommerce/scenarios/01-external-reconnect-sync.json","targets":["ecommerce.spec.external-data-sync.external-stock.901d"],"desc":"Follow catalog changes until the browser goes offline, then ignore updates after restoration.","file":"client/src/App.tsx","edits":[{"find":" const cartObservationRef = useRef(0);\n\n function applyCartResponse","replace":" const cartObservationRef = useRef(0);\n const acceptCatalogUpdates = useRef(true);\n useEffect(() => {\n const stopCatalogRecovery = () => { acceptCatalogUpdates.current = false; };\n window.addEventListener(\"offline\", stopCatalogRecovery);\n return () => window.removeEventListener(\"offline\", stopCatalogRecovery);\n }, []);\n\n function applyCartResponse"},{"find":" socket.on(\"items:update\", (payload: { items: Item[] }) => setItems(payload.items));","replace":" socket.on(\"items:update\", (payload: { items: Item[] }) => {\n if (acceptCatalogUpdates.current) setItems(payload.items);\n });"}]},{"id":"open-review-list-ignores-live-update","scenario":"tracks/ecommerce/scenarios/progression-open-list-live.json","targets":["ecommerce.spec.live-state.open-list.902a"],"desc":"Ignore committed review updates in a detail view that is already open.","file":"client/src/App.tsx","edits":[{"find":" setItemDetail({ reviews: payload.reviews, average: payload.average });","replace":" // mutant: the already-open review list ignores committed updates"}]},{"id":"open-review-list-renders-each-review-twice","scenario":"tracks/ecommerce/scenarios/progression-open-list-live.json","targets":["ecommerce.spec.live-state.open-list.902a"],"desc":"Render every committed review twice in the already-open list.","file":"client/src/App.tsx","edits":[{"find":" reviews.map((r) => (","replace":" [...reviews, ...reviews].map((r) => ("}]},{"id":"cancel-does-not-restore-stock-feature","scenario":"tracks/ecommerce/scenarios/02-order-cancellation-core.json","targets":["ecommerce.returns-pricing.cancellation-and-return.3a"],"desc":"Cancellation commits but restores zero units to each recorded warehouse row.","file":"server/src/index.ts","edits":[{"find":" [l.item_id, l.warehouse_id, l.quantity]\n );\n }\n await refundCredit(client, orderRow.rows[0]);\n await client.query(`UPDATE orders SET status = 'cancelled' WHERE id = $1`, [orderId]);","replace":" [l.item_id, l.warehouse_id, 0]\n );\n }\n await refundCredit(client, orderRow.rows[0]);\n await client.query(`UPDATE orders SET status = 'cancelled' WHERE id = $1`, [orderId]);"}]},{"id":"cancellation-accounting-loses-stock-restoration","scenario":"tracks/ecommerce/scenarios/02-invariants.json","targets":["ecommerce.returns-pricing.refund-accounting.203a"],"desc":"Cancellation removes revenue and changes order status, but loses the original warehouse stock restoration. The native refund-accounting assertion must detect this.","file":"server/src/index.ts","edits":[{"find":" [l.item_id, l.warehouse_id, l.quantity]\n );\n }\n await refundCredit(client, orderRow.rows[0]);\n await client.query(`UPDATE orders SET status = 'cancelled' WHERE id = $1`, [orderId]);","replace":" [l.item_id, l.warehouse_id, 0]\n );\n }\n await refundCredit(client, orderRow.rows[0]);\n await client.query(`UPDATE orders SET status = 'cancelled' WHERE id = $1`, [orderId]);"}]},{"id":"cancel-does-not-restore-stock-fresh-client","scenario":"tracks/ecommerce/scenarios/02-self-contained.json","targets":["ecommerce.inventory-operations.stock-conservation.202b","ecommerce.inventory-operations.stock-conservation.202c"],"desc":"Cancellation commits but restores zero units, so a fresh client reads the persisted shortfall.","file":"server/src/index.ts","edits":[{"find":" [l.item_id, l.warehouse_id, l.quantity]\n );\n }\n await refundCredit(client, orderRow.rows[0]);\n await client.query(`UPDATE orders SET status = 'cancelled' WHERE id = $1`, [orderId]);","replace":" [l.item_id, l.warehouse_id, 0]\n );\n }\n await refundCredit(client, orderRow.rows[0]);\n await client.query(`UPDATE orders SET status = 'cancelled' WHERE id = $1`, [orderId]);"}]},{"id":"cancel-restores-stock-but-keeps-pending-status","scenario":"tracks/ecommerce/scenarios/02-order-cancellation-history.json","targets":["ecommerce.returns-pricing.cancellation-and-return.3b"],"desc":"Cancellation restores allocations but writes pending back to order history.","file":"server/src/index.ts","edits":[{"find":"await client.query(`UPDATE orders SET status = 'cancelled' WHERE id = $1`, [orderId]);","replace":"await client.query(`UPDATE orders SET status = 'pending' WHERE id = $1`, [orderId]);"}]},{"id":"operator-authorization-allows-customer-transfer","scenario":"tracks/ecommerce/scenarios/02-strengthened.json","targets":["ecommerce.operations-access.operator-authorization.201a"],"desc":"The transfer route replaces its administrator gate with ordinary authentication.","file":"server/src/index.ts","edits":[{"find":"app.post(\n \"/api/admin/transfer\",\n requireAdmin,","replace":"app.post(\n \"/api/admin/transfer\",\n requireAuth,"}]},{"id":"customer-can-ship-order-direct-1-1","scenario":"tracks/ecommerce/scenarios/02-server-actions.json","targets":["ecommerce.operations-access.operator-authorization.201c"],"desc":"The shipping route replaces its staff gate with ordinary authentication.","file":"server/src/index.ts","edits":[{"find":"app.post(\n \"/api/fulfilment/ship\",\n requireStaff,","replace":"app.post(\n \"/api/fulfilment/ship\",\n requireAuth,"}]},{"id":"customer-can-cancel-foreign-order-1-1","scenario":"tracks/ecommerce/scenarios/02-server-actions.json","targets":["ecommerce.operations-access.order-owner.204a"],"desc":"Cancellation retains authentication and pending-state validation but drops order ownership.","file":"server/src/index.ts","edits":[{"find":"app.post(\n \"/api/orders/:id/cancel\",\n requireAuth,\n asyncHandler(async (req, res) => {\n const orderId = Number(req.params.id);\n const accountId = req.account!.id;\n const client = await pool.connect();\n try {\n await client.query(\"BEGIN\");\n const orderRow = await client.query(`SELECT * FROM orders WHERE id = $1 FOR UPDATE`, [orderId]);\n if (orderRow.rowCount === 0 || orderRow.rows[0].account_id !== accountId) {","replace":"app.post(\n \"/api/orders/:id/cancel\",\n requireAuth,\n asyncHandler(async (req, res) => {\n const orderId = Number(req.params.id);\n const accountId = req.account!.id;\n const client = await pool.connect();\n try {\n await client.query(\"BEGIN\");\n const orderRow = await client.query(`SELECT * FROM orders WHERE id = $1 FOR UPDATE`, [orderId]);\n if (orderRow.rowCount === 0) {"}]},{"id":"queue-depth-lags-one-order","scenario":"tracks/ecommerce/scenarios/02-fulfilment-live.json","targets":["ecommerce.operations-access.fulfilment-queue.1a"],"desc":"The queue renders every order but its visible depth remains one behind.","file":"client/src/App.tsx","edits":[{"find":"{queue.depth}","replace":"{Math.max(0, queue.depth - 1)}"}]},{"id":"customer-sees-fulfilment-navigation","scenario":"tracks/ecommerce/scenarios/02-features.json","targets":["ecommerce.operations-access.fulfilment-queue.1d"],"desc":"Expose the protected staff area to signed-in customers, including its navigation and content.","file":"client/src/App.tsx","edits":[{"find":" {account && (account.isStaff || account.isAdmin) && (\n
)}","replace":"
)}"}]},{"id":"purchase-does-not-broadcast-fulfilment-queue","scenario":"tracks/ecommerce/scenarios/02-fulfilment-live.json","targets":["ecommerce.spec.live-state.fulfilment-queue.1a"],"desc":"A direct purchase commits its pending order but omits the fulfilment queue broadcast, so an open staff queue never learns about the new order.","file":"server/src/index.ts","edits":[{"find":" await broadcastCatalog();\n await broadcastOrders(accountId);\n await broadcastFulfilment();\n await broadcastRecommended(accountId);\n res.json({ ok: true });\n })\n);\n\n// ---------- cart routes ----------","replace":" await broadcastCatalog();\n await broadcastOrders(accountId);\n // mutant: the new pending order is not pushed to open fulfilment queues\n await broadcastRecommended(accountId);\n res.json({ ok: true });\n })\n);\n\n// ---------- cart routes ----------"}]},{"id":"admin-state-change-is-not-broadcast","scenario":"tracks/ecommerce/scenarios/02-low-stock.json","targets":["ecommerce.spec.live-state.inventory-dashboard.5a"],"desc":"Changed admin dashboard state is never broadcast to open admin views, so a customer purchase that drops an item to ten units does not re-enter the low-stock list live.","file":"server/src/index.ts","edits":[{"find":" lastAdminJson = adminJson;\n io.to(\"admin\").emit(\"admin:update\", adminState);","replace":" lastAdminJson = adminJson;\n // mutant: changed admin state is not broadcast"}]},{"id":"admin-sockets-do-not-join-admin-room","scenario":"tracks/ecommerce/scenarios/02-operational-category-totals.json","targets":["ecommerce.spec.live-state.sales-dashboard.5b"],"desc":"Admin sockets receive their dashboard state on connection but never join the admin room, so a customer purchase does not update the open category totals live.","file":"server/src/index.ts","edits":[{"find":" if (acc.isAdmin) socket.join(\"admin\");","replace":" // mutant: admin sockets never join the admin room"}]},{"id":"transfer-overdraft-guard-skips-bulk-transfers","scenario":"tracks/ecommerce/scenarios/02-transfer-overdraw.json","targets":["ecommerce.spec.transactional-integrity.stock-transfer-overdraw.2c"],"desc":"The insufficient-stock guard is only evaluated for transfers under 1000 units, so a bulk transfer that overdraws the source warehouse commits instead of being refused.","file":"server/src/index.ts","edits":[{"find":" if (available < qty) {","replace":" if (available < qty && qty < 1000) {"}]},{"id":"transfer-does-not-publish-warehouse-totals","scenario":"tracks/ecommerce/scenarios/02-transfer-totals.json","targets":["ecommerce.spec.live-state.stock-transfers.2b"],"desc":"A transfer commits but answers with the pre-transfer admin snapshot and admin state is never broadcast, so the open warehouse totals do not move.","file":"server/src/index.ts","edits":[{"find":" const client = await pool.connect();\n try {\n await client.query(\"BEGIN\");\n // Lock both warehouse rows","replace":" const state = await buildAdminState();\n const client = await pool.connect();\n try {\n await client.query(\"BEGIN\");\n // Lock both warehouse rows"},{"find":" await broadcastCatalog();\n const state = await buildAdminState();\n res.json(state);\n })\n);\n\napp.post(\n \"/api/admin/price\",","replace":" await broadcastCatalog();\n res.json(state);\n })\n);\n\napp.post(\n \"/api/admin/price\","},{"find":" lastAdminJson = adminJson;\n io.to(\"admin\").emit(\"admin:update\", adminState);","replace":" lastAdminJson = adminJson;\n // mutant: changed admin state is not broadcast"}]},{"id":"credit-checkout-ignores-wallet","desc":"A credit checkout pays entirely externally despite available credit.","scenario":"tracks/ecommerce/scenarios/progression-store-credit.json","targets":["ecommerce.feature.store-credit.store-credit-750.750a"],"file":"server/src/credit.ts","edits":[{"find":" const creditMinor = Math.min(Number(account.rows[0].credit_minor), totalMinor);","replace":" const creditMinor = 0;"}]},{"id":"credit-grant-replay-increments-balance","desc":"Replaying a grant applies its credit to the wallet again.","scenario":"tracks/ecommerce/scenarios/progression-store-credit.json","targets":["ecommerce.spec.store-credit.production-752.752a"],"file":"server/src/credit.ts","edits":[{"find":" if (!existing.rows.length) {","replace":" if (existing.rows.length) await client.query('UPDATE account SET credit_minor=credit_minor+$1 WHERE id=$2', [amountMinor, accountId]);\n if (!existing.rows.length) {"}]},{"id":"customer-can-grant-credit","desc":"Customer authentication is accepted without staff authorization.","scenario":"tracks/ecommerce/scenarios/progression-store-credit.json","targets":["ecommerce.spec.store-credit.production-753.753a"],"file":"server/src/credit.ts","edits":[{"find":" app.post('/api/staff/credit', auth, staff, async (req, res) => {","replace":" app.post('/api/staff/credit', auth, async (req, res) => {"}]},{"id":"split-refund-does-not-restore-credit","desc":"The refund is recorded but its original wallet credit is not restored.","scenario":"tracks/ecommerce/scenarios/progression-split-tender-refunds.json","targets":["ecommerce.feature.split-tender-refunds.split-tender-refunds-751.751a"],"file":"server/src/progression.ts","edits":[{"find":" await refundCredit(client, order.rows[0]);","replace":" // mutant: omit wallet restoration"}]},{"id":"split-refund-duplicates-credit","desc":"A refund credits the wallet twice while recording one refund.","scenario":"tracks/ecommerce/scenarios/progression-split-tender-refunds.json","targets":["ecommerce.spec.split-tender-refunds.production-756.756a"],"file":"server/src/credit.ts","edits":[{"find":"[delta, order.account_id]);","replace":"[delta * 2, order.account_id]);"}]},{"id":"subscription-skips-due-purchase","desc":"Due deliveries are recorded as skipped although stock is available.","scenario":"tracks/ecommerce/scenarios/progression-subscriptions.json","targets":["ecommerce.feature.subscriptions.subscriptions-760.760a"],"file":"server/src/subscriptions.ts","edits":[{"find":" if (stock.rows.reduce((sum, row) => sum + row.quantity, 0) >= subscription.quantity) {","replace":" if (false && stock.rows.reduce((sum, row) => sum + row.quantity, 0) >= subscription.quantity) {"}]},{"id":"subscription-allows-foreign-cancellation","desc":"A customer can cancel another customer subscription.","scenario":"tracks/ecommerce/scenarios/progression-subscriptions.json","targets":["ecommerce.spec.subscriptions.production-762.762a"],"file":"server/src/subscriptions.ts","edits":[{"find":" if (!row || row.account_id !== req.account!.id) {","replace":" if (!row) {"}]},{"id":"subscription-pause-is-not-recorded","desc":"Pause acknowledges the request but the subscription remains active.","scenario":"tracks/ecommerce/scenarios/progression-subscriptions.json","targets":["ecommerce.spec.subscriptions.production-763.763a"],"file":"server/src/subscriptions.ts","edits":[{"find":"UPDATE purchase_subscription SET status='paused',paused_at=now() WHERE id=$1","replace":"UPDATE purchase_subscription SET status='active',paused_at=now() WHERE id=$1"}]},{"id":"credit-checkout-retains-purchased-cart","scenario":"tracks/ecommerce/scenarios/progression-store-credit.json","targets":["ecommerce.spec.store-credit.production-754.754a"],"desc":"The purchased cart remains available instead of being consumed by checkout.","file":"server/src/progression.ts","edits":[{"find":" await client.query(`DELETE FROM cart_item WHERE cart_id = $1`, [cart.rows[0].id]);","replace":" // Mutation: keep checked-out cart lines."}]},{"id":"pending-subscriptions-are-cleared-at-startup","desc":"Restart erases pending subscription work while preserving ordinary timer execution.","file":"server/src/subscriptions.ts","scenario":"tracks/ecommerce/scenarios/progression-subscriptions.json","targets":["ecommerce.spec.subscriptions.production-761.761a"],"edits":[{"find":" `);\n}\n\nexport function registerSubscriptions","replace":" `);\n await pool.query(\"UPDATE purchase_subscription SET status='cancelled' WHERE status='active'\");\n}\n\nexport function registerSubscriptions"}]},{"id":"credit-balance-is-cleared-at-startup","desc":"Restart clears an issued wallet balance while leaving accounts present.","file":"server/src/credit.ts","scenario":"tracks/ecommerce/scenarios/progression-store-credit.json","targets":["ecommerce.spec.store-credit.production-755.755a"],"edits":[{"find":" `);\n}\n\nexport async function spendCredit","replace":" `);\n await pool.query(\"UPDATE account SET credit_minor=0\");\n}\n\nexport async function spendCredit"}]},{"id":"bundle-definition-loses-component-quantity","scenario":"tracks/ecommerce/scenarios/progression-product-bundles.json","targets":["ecommerce.feature.product-bundles.product-bundles.740a"],"desc":"definition loses component quantity","file":"server/src/bundles.ts","edits":[{"find":"values.push({ ...component, itemId: item.rows[0].id });","replace":"values.push({ ...component, quantity: 1, itemId: item.rows[0].id });"}]},{"id":"bundle-catalog-write-allows-customers","scenario":"tracks/ecommerce/scenarios/progression-product-bundles.json","targets":["ecommerce.spec.bundle-integrity.bundle-743.743a"],"desc":"catalog write allows customers","file":"server/src/bundles.ts","edits":[{"find":"if (!actor?.is_admin && actor?.staff_role !== 'catalog')","replace":"if (false)"}]},{"id":"bundle-checkout-price-not-snapshot","scenario":"tracks/ecommerce/scenarios/progression-bundle-checkout.json","targets":["ecommerce.feature.bundle-checkout.bundle-checkout.741a"],"desc":"checkout price not snapshot","file":"server/src/bundles.ts","edits":[{"find":"[cart.rows[0].id, bundleId, bundle.price, JSON.stringify(allocations), JSON.stringify(bundle.bundle_components)]","replace":"[cart.rows[0].id, bundleId, bundle.price + 1, JSON.stringify(allocations), JSON.stringify(bundle.bundle_components)]"}]},{"id":"bundle-expiry-does-not-release-components","scenario":"tracks/ecommerce/scenarios/progression-bundle-checkout.json","targets":["ecommerce.spec.bundle-integrity.bundle-746.746a"],"desc":"expiry does not release components","file":"server/src/progression.ts","edits":[{"find":"await releaseBundle(client, bundle.rows[0].component_allocations);","replace":"/* mutant: component holds leak after expiration */"}]},{"id":"bundle-return-loses-original-components","scenario":"tracks/ecommerce/scenarios/progression-bundle-returns.json","targets":["ecommerce.feature.bundle-returns.bundle-returns.742a"],"desc":"return loses original components","file":"server/src/bundles.ts","edits":[{"find":"await releaseBundle(client, line.component_allocations);","replace":"/* mutant: purchased components are not restored */"}]},{"id":"bundle-return-replay-restocks-again","scenario":"tracks/ecommerce/scenarios/progression-bundle-returns.json","targets":["ecommerce.spec.bundle-integrity.bundle-742.742b"],"desc":"return replay restocks again","file":"server/src/bundles.ts","edits":[{"find":"WHERE order_id=$1 AND is_bundle AND NOT returned FOR UPDATE","replace":"WHERE order_id=$1 AND is_bundle FOR UPDATE"}]},{"id":"bundle-return-crosses-account-boundary","scenario":"tracks/ecommerce/scenarios/progression-bundle-returns.json","targets":["ecommerce.spec.bundle-integrity.bundle-748.748a"],"desc":"return crosses account boundary","file":"server/src/bundles.ts","edits":[{"find":"WHERE id=$1 AND account_id=$2 AND status IN ('shipped','delivered')","replace":"WHERE id=$1 AND $2::integer=$2::integer AND status IN ('shipped','delivered')"}]},{"id":"bundle-components-can-overdraw","scenario":"tracks/ecommerce/scenarios/progression-bundle-checkout.json","targets":["ecommerce.spec.bundle-integrity.bundle-744.744a","ecommerce.spec.bundle-integrity.bundle-745.745a"],"desc":"components can overdraw","file":"server/src/bundles.ts","edits":[{"find":"if (rows.rows.reduce((sum, row) => sum + row.quantity, 0) < component.quantity) throw new Error('A component is unavailable');","replace":"// mutant: incomplete component reservation is accepted"}]},{"id":"bundle-checkout-reuses-reservation","scenario":"tracks/ecommerce/scenarios/progression-bundle-checkout.json","targets":["ecommerce.spec.bundle-integrity.bundle-747.747a"],"desc":"checkout reuses reservation","file":"server/src/progression.ts","edits":[{"find":"await client.query(`DELETE FROM cart_item WHERE cart_id = $1`, [cart.rows[0].id]);","replace":"// mutant: cart survives checkout"}]},{"id":"return-after-support-refund-is-blocked","scenario":"tracks/ecommerce/scenarios/progression-support-return-interaction.json","targets":["ecommerce.feature.split-tender-refunds.return-refund-interaction.757a"],"desc":"Reject a valid physical return after a financial refund.","file":"server/src/index.ts","edits":[{"find":" if (lineRow.rows[0].returned) {","replace":" if (lineRow.rows[0].returned || Number(orderRow.rows[0].refund_total) > 0) {"}]},{"id":"support-refund-after-return-pays-twice","scenario":"tracks/ecommerce/scenarios/progression-support-return-interaction.json","targets":["ecommerce.feature.split-tender-refunds.return-refund-interaction.757b"],"desc":"Pay the full order again after a physical return.","file":"server/src/progression.ts","edits":[{"find":" await client.query(`UPDATE orders SET refund_total = total, status = CASE","replace":" await client.query(`UPDATE orders SET refund_total = refund_total + total, status = CASE"}]},{"id":"progression-support-history-anonymous-leak","scenario":"tracks/ecommerce/scenarios/progression-support-history.json","targets":["ecommerce.spec.access-control.support-history-logout.612d"],"desc":"Return private support subjects to signed-out visitors while preserving authenticated ownership filtering.","file":"server/src/progression.ts","edits":[{"find":" if (!account) return [];\n const where = account.isAdmin || account.isStaff ? \"TRUE\" : \"sc.account_id = $1\";\n const values = account.isAdmin || account.isStaff ? [] : [account.id];","replace":" const where = !account || account.isAdmin || account.isStaff ? \"TRUE\" : \"sc.account_id = $1\";\n const values = !account || account.isAdmin || account.isStaff ? [] : [account.id];"}]},{"id":"checkout-crash-integrity","scenario":"tracks/ecommerce/scenarios/progression-checkout-crash.json","targets":["ecommerce.spec.state-durability.checkout-crash-integrity.910a"],"desc":"A lifecycle callback changes a prepared or cleared cart to quantity two, leaving neither a legal rollback nor a complete checkout.","file":"server/src/index.ts","edits":[{"find":" await initializeProgressionSchema(pool);","replace":" await initializeProgressionSchema(pool);\n await pool.query(`INSERT INTO cart_item (cart_id, item_id, quantity) SELECT c.id, MIN(oi.item_id), 2 FROM cart c JOIN orders o ON o.account_id=c.account_id JOIN order_item oi ON oi.order_id=o.id GROUP BY c.id ON CONFLICT (cart_id,item_id) DO UPDATE SET quantity=2`);"}]},{"id":"checkout-crash-durability","scenario":"tracks/ecommerce/scenarios/progression-checkout-crash.json","targets":["ecommerce.spec.state-durability.checkout-crash-durability.910b"],"desc":"A lifecycle callback corrupts earlier order totals. The unchanged prepared snapshots and acknowledged baseline must expose the damage.","file":"server/src/index.ts","edits":[{"find":" await initializeProgressionSchema(pool);","replace":" await initializeProgressionSchema(pool);\n await pool.query('UPDATE orders SET total=0');"}]},{"id":"review-script-unsafe-render","scenario":"tracks/ecommerce/scenarios/progression-review-script.json","targets":["ecommerce.progression.review-access-specifications.stored-review-script.9180a"],"desc":"Render stored review text as HTML so it executes in another customer session.","file":"client/src/App.tsx","edits":[{"find":"
{r.comment}
","replace":"
"}]},{"id":"review-script-reject-all","scenario":"tracks/ecommerce/scenarios/progression-review-script.json","targets":["ecommerce.progression.review-access-specifications.stored-review-script.9180a"],"desc":"Reject all nonempty reviews, including the required benign review; absence of script is insufficient.","file":"server/src/index.ts","edits":[{"find":"const { rating, comment } = req.body ?? {};","replace":"const { rating, comment } = req.body ?? {};\n if (String(comment).length > 0) { res.status(400).json({ error: \"Review rejected\" }); return; }"}]}]},"spacetime":{"schemaVersion":3,"fixtureSha256":"7ba1f548e89f461b95b5caf843b0fbcf2b81278428d02869d7f47e1a199eaf6e","backend":"spacetime","track":"ecommerce","note":"Mutation definitions for the SpacetimeDB ecommerce reference.","mutations":[{"id":"recommendation-dismissal-lost-on-reconnect","scenario":"tracks/ecommerce/scenarios/progression-recommendation-feedback.json","targets":["ecommerce.spec.state-durability.recommendation-feedback-restart.504c"],"desc":"Erase saved recommendation dismissals when a browser reconnects. This controls reconnect persistence, not backend restart alone.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"export const onConnect = spacetimedb.clientConnected((_ctx) => {});","replace":"export const onConnect = spacetimedb.clientConnected((ctx) => { for (const row of ctx.db.recommendationDismissal.iter()) ctx.db.recommendationDismissal.id.delete(row.id); });"}]},{"id":"pending-order-item-return-accepted","scenario":"tracks/ecommerce/scenarios/progression-order-return-boundary.json","targets":["ecommerce.returns-pricing.cancellation-and-return.3f"],"desc":"Accept a pending order return and restore its stock before shipment.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"if (!['shipped', 'delivered'].includes(order.status)) throw new SenderError('Order has not shipped yet.');","replace":"if (!['pending', 'shipped', 'delivered'].includes(order.status)) throw new SenderError('Order has not shipped yet.');"}]},{"id":"staff-admin-access-survives-role-removal","scenario":"tracks/ecommerce/scenarios/progression-staff-roles.json","targets":["ecommerce.spec.access-control.staff-role-revocation.621d"],"desc":"Keep administrator access after changing the assigned role back to staff.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"ctx.db.account.id.update({ ...target, isAdmin: role === 'admin' });","replace":"ctx.db.account.id.update({ ...target, isAdmin: target.isAdmin || role === 'admin' });"}]},{"id":"shipping-counts-sale-twice","scenario":"tracks/ecommerce/scenarios/progression-shipping-accounting.json","targets":["ecommerce.inventory-operations.shipping-accounting.202e"],"desc":"Shipping succeeds but doubles the completed sale value in authoritative revenue.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" ctx.db.customerOrder.id.update({ ...order, status: 'shipped' });","replace":" ctx.db.customerOrder.id.update({ ...order, status: 'shipped', total: order.total * 2 });"}]},{"id":"restock-client-snapshot-overwrites-concurrent-purchases","scenario":"tracks/ecommerce/scenarios/01-restock-race.json","targets":["ecommerce.spec.concurrency-safety.restock-race.202a"],"desc":"Compute absolute restock quantity when the administrator edits the form and store that captured value in the reducer. A fixed 500 ms submission delay widens the stale-write window. Serial purchases and restocks still work; intervening purchases can be overwritten. This is a stale-form lost update, not a race inside an atomic reducer.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"ctx.db.stock.insert({ ...existing, quantity: existing.quantity + quantity });\n } else {\n ctx.db.stock.insert({ item_id: itemId, warehouse_id: warehouseId, quantity });\n }\n for (const alert of","replace":"ctx.db.stock.insert({ ...existing, quantity });\n } else {\n ctx.db.stock.insert({ item_id: itemId, warehouse_id: warehouseId, quantity });\n }\n for (const alert of"},{"file":"client/src/components/AdminPanel.tsx","find":"onChange={(e) => setRestockInputs((v) => ({ ...v, [k]: e.target.value }))}","replace":"onChange={(e) => setRestockInputs((v) => ({ ...v, [k]: String(stockOf(item.id, wh.id) + Number(e.target.value)) }))}"},{"file":"client/src/App.tsx","find":" await conn?.reducers.adminRestock({ itemId, warehouseId, quantity });","replace":" // Mutant: widen the stale form submission window without changing serial behavior.\n await new Promise(resolve => setTimeout(resolve, 500));\n await conn?.reducers.adminRestock({ itemId, warehouseId, quantity });"}]},{"id":"signup-binds-the-new-account-to-the-admin-session","scenario":"tracks/ecommerce/scenarios/01-account-create.json","targets":["ecommerce.feature.accounts.accounts.1a"],"desc":"Create the requested account but bind the new browser session to the administrator, so account creation no longer signs the visitor in as the account it created.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" const acc = ctx.db.account.insert({\n id: 0n,\n username: uname,\n passwordHash: hashPassword(password),\n isAdmin: false,\n isStaff: false,\n });\n\n const existingSession = ctx.db.session.identity.find(ctx.sender);\n if (existingSession) {\n ctx.db.session.identity.update({ ...existingSession, accountId: acc.id });\n } else {\n ctx.db.session.insert({ identity: ctx.sender, accountId: acc.id });\n }","replace":" const acc = ctx.db.account.insert({\n id: 0n,\n username: uname,\n passwordHash: hashPassword(password),\n isAdmin: false,\n isStaff: false,\n });\n\n const signedInAccount = ctx.db.account.username.find('admin') ?? acc;\n const existingSession = ctx.db.session.identity.find(ctx.sender);\n if (existingSession) {\n ctx.db.session.identity.update({ ...existingSession, accountId: signedInAccount.id });\n } else {\n ctx.db.session.insert({ identity: ctx.sender, accountId: signedInAccount.id });\n }"}]},{"id":"duplicate-signup-is-silently-ignored","scenario":"tracks/ecommerce/scenarios/01-account-duplicate.json","targets":["ecommerce.feature.accounts.accounts.1b"],"desc":"Return success for a taken username without creating a session or surfacing the required refusal.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" if (existing) throw new SenderError('That username is already taken.');","replace":" if (existing) return; // mutant: duplicate signup is silently accepted"}]},{"id":"signin-does-not-verify-the-password","scenario":"tracks/ecommerce/scenarios/01-account-password.json","targets":["ecommerce.feature.accounts.accounts.1c"],"desc":"Accept a known username without comparing the supplied password hash.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" if (!acc || acc.passwordHash !== hashPassword(password)) {","replace":" if (!acc) {"}]},{"id":"signout-keeps-the-account-session","scenario":"tracks/ecommerce/scenarios/01-account-signout.json","targets":["ecommerce.feature.accounts.accounts.1d"],"desc":"Leave the current account session in place when the visitor signs out.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" if (existingSession) ctx.db.session.identity.delete(ctx.sender);","replace":" // mutant: sign out keeps the current account session"}]},{"id":"session-token-is-not-persisted-for-reload","scenario":"tracks/ecommerce/scenarios/01-account-reload.json","targets":["ecommerce.spec.state-durability.session-reload.1e"],"desc":"Discard the connection token instead of persisting it, so a reload receives a new identity with no account session.","file":"client/src/App.tsx","edits":[{"find":" if (token) localStorage.setItem('auth_token', token);","replace":" if (token) localStorage.removeItem('auth_token');"}]},{"id":"catalog-seeds-the-wrong-air-purifier-price","scenario":"tracks/ecommerce/scenarios/01-catalog-values.json","targets":["ecommerce.feature.catalog.catalog-values.2a"],"desc":"Seed Air Purifier with an incorrect stored price while leaving the rest of the catalog intact.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" ['Air Purifier', 189.0, 60, 40, 'Home'],","replace":" ['Air Purifier', 999.0, 60, 40, 'Home'],"}]},{"id":"catalog-tie-breaks-in-reverse-alphabetical-order--01-catalog-ranking","scenario":"tracks/ecommerce/scenarios/01-catalog-ranking.json","targets":["ecommerce.feature.catalog.catalog-ranking.2b"],"desc":"Reverse the specified alphabetical tie-breaker. This necessarily breaks both the initial sequence and the post-purchase sequence in the same scenario.","file":"client/src/App.tsx","edits":[{"find":" return a.name.localeCompare(b.name);","replace":" return b.name.localeCompare(a.name);"}]},{"id":"catalog-tie-breaks-in-reverse-alphabetical-order--01-core","scenario":"tracks/ecommerce/scenarios/01-core.json","targets":["ecommerce.spec.live-state.ranking.2c"],"desc":"Reverse the specified alphabetical tie-breaker. This necessarily breaks both the initial sequence and the post-purchase sequence in the same scenario.","file":"client/src/App.tsx","edits":[{"find":" return a.name.localeCompare(b.name);","replace":" return b.name.localeCompare(a.name);"}]},{"id":"purchase-does-not-update-ranking-count","scenario":"tracks/ecommerce/scenarios/01-core.json","targets":["ecommerce.spec.live-state.ranking.2c"],"desc":"Complete the purchase but leave its popularity count unchanged, so open storefronts cannot rank the purchased item first.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" bumpPurchaseCount(ctx, itemId, quantity);","replace":" // mutant: buy-now never advances the ranking count"}]},{"id":"signed-out-purchase-bypasses-account-check","scenario":"tracks/ecommerce/scenarios/progression-signed-out-purchase.json","targets":["ecommerce.spec.access-control.signed-out-purchase.3a"],"desc":"Expose the guest purchase button and accept its purchase as the existing administrator. The stock observation then exercises the broken account boundary; normal signed-in purchases remain unchanged.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"export const buyNow = spacetimedb.reducer({ itemId: t.u64() }, (ctx, { itemId }) => {\n const acc = requireAccount(ctx);","replace":"export const buyNow = spacetimedb.reducer({ itemId: t.u64() }, (ctx, { itemId }) => {\n const acc = getAccountId(ctx) === null ? ctx.db.account.username.find('admin')! : requireAccount(ctx);"},{"file":"client/src/components/ItemCard.tsx","find":" {isSignedIn && (","replace":" {true && ("}]},{"id":"buy-now-creates-orders-without-reserving-stock--01-buying","scenario":"tracks/ecommerce/scenarios/01-buying.json","targets":["ecommerce.spec.live-state.purchase-stock.3b"],"desc":"Create purchase orders without reserving inventory. The same defect necessarily breaks live purchase stock and the sell-out portion of the stock-limit check.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" const allocations = decrementStockTracked(ctx, itemId, quantity);","replace":" const allocations: Array<{ warehouseId: bigint; quantity: number }> = [];"}]},{"id":"buy-now-creates-orders-without-reserving-stock--stock-limit","scenario":"tracks/ecommerce/scenarios/progression-stock-limit.json","targets":["ecommerce.spec.concurrency-safety.stock-limit.3d"],"desc":"Create purchase orders without reserving inventory. The same defect necessarily breaks live purchase stock and the sell-out portion of the stock-limit check.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" const allocations = decrementStockTracked(ctx, itemId, quantity);","replace":" const allocations: Array<{ warehouseId: bigint; quantity: number }> = [];"}]},{"id":"restock-race-records-wrong-order-total","scenario":"tracks/ecommerce/scenarios/01-restock-race.json","targets":["ecommerce.spec.concurrency-safety.restock-race.202a"],"desc":"Purchases preserve stock and visible order counts but record the wrong booked total. Native mixed-race reconciliation must reject them.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" total: Math.round(price * 100) * quantity / 100,\n status: 'pending',","replace":" total: Math.round(price * 100) * quantity / 100 + 1,\n status: 'pending',"}]},{"id":"buy-now-records-the-wrong-order-total","scenario":"tracks/ecommerce/scenarios/progression-purchasing.json","targets":["ecommerce.feature.purchasing.purchase-order.3c"],"desc":"Record a completed buy-now order one dollar above the stored item price.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" total: Math.round(price * 100) * quantity / 100,\n status: 'pending',","replace":" total: Math.round(price * 100) * quantity / 100 + 1,\n status: 'pending',"}]},{"id":"existing-cart-line-does-not-increment-basic-cart","scenario":"tracks/ecommerce/scenarios/progression-cart-checkout.json","targets":["ecommerce.feature.cart-checkout.cart.4a"],"desc":"Write an existing cart line back without incrementing its quantity.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"ctx.db.cartItem.id.update({ ...existing, quantity: existing.quantity + 1 });","replace":"ctx.db.cartItem.id.update({ ...existing, quantity: existing.quantity });"}]},{"id":"cart-is-deleted-when-owner-disconnects","scenario":"tracks/ecommerce/scenarios/01-cart.json","targets":["ecommerce.spec.state-durability.cart-reload.4b"],"desc":"Delete the account cart on transport disconnect. Reload loses stored cart contents even after the same account signs in again; account and session records remain intact.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"export const onDisconnect = spacetimedb.clientDisconnected((_ctx) => {});","replace":"export const onDisconnect = spacetimedb.clientDisconnected((ctx) => {\n const accountId = getAccountId(ctx);\n if (accountId !== null) for (const row of [...ctx.db.cartItem.byAccountItem.filter(accountId)]) ctx.db.cartItem.id.delete(row.id);\n});"}]},{"id":"signin-binds-the-second-client-to-a-different-account","scenario":"tracks/ecommerce/scenarios/01-cart.json","targets":["ecommerce.spec.live-state.shared-cart.4c"],"desc":"Authenticate valid credentials but bind the second connection to the administrator account, so two sessions for one customer do not share the customer's cart.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" const existingSession = ctx.db.session.identity.find(ctx.sender);\n if (existingSession) {\n ctx.db.session.identity.update({ ...existingSession, accountId: acc.id });\n } else {\n ctx.db.session.insert({ identity: ctx.sender, accountId: acc.id });\n }\n }\n);\n\nexport const signOut","replace":" const wrongAccount = ctx.db.account.username.find('admin') ?? acc;\n const existingSession = ctx.db.session.identity.find(ctx.sender);\n if (existingSession) {\n ctx.db.session.identity.update({ ...existingSession, accountId: wrongAccount.id });\n } else {\n ctx.db.session.insert({ identity: ctx.sender, accountId: wrongAccount.id });\n }\n }\n);\n\nexport const signOut"}]},{"id":"checkout-does-not-empty-the-basic-cart","scenario":"tracks/ecommerce/scenarios/progression-cart-checkout.json","targets":["ecommerce.feature.cart-checkout.cart.4d"],"desc":"Leave completed checkout lines in the durable cart.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" for (const line of lines) ctx.db.cartItem.id.delete(line.id);","replace":" // mutant: checked-out cart lines remain"}]},{"id":"new-review-is-accepted-without-being-stored","scenario":"tracks/ecommerce/scenarios/01-review-visibility.json","targets":["ecommerce.feature.reviews.reviews.6a"],"desc":"Accept an eligible new review but omit its durable insert, so neither author nor visitor can see it.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" ctx.db.review.insert({\n id: 0n,\n itemId,\n accountId: acc.id,\n rating,\n comment,\n createdAt: ctx.timestamp,\n });","replace":" // mutant: accepted review is not persisted"}]},{"id":"repeat-review-inserts-a-second-row","scenario":"tracks/ecommerce/scenarios/01-review-uniqueness.json","targets":["ecommerce.spec.transactional-integrity.unique-review.6b"],"desc":"Insert a second review row instead of updating the customer's existing item review.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" ctx.db.review.id.update({ ...existing, rating, comment, createdAt: ctx.timestamp });","replace":" ctx.db.review.insert({ id: 0n, itemId, accountId: acc.id, rating, comment, createdAt: ctx.timestamp });"}]},{"id":"review-average-counts-rows-instead-of-ratings","scenario":"tracks/ecommerce/scenarios/01-review-rating-live.json","targets":["ecommerce.spec.live-state.rating.6c"],"desc":"Compute the live average from a constant per row rather than each stored rating.","file":"client/src/components/ItemDetail.tsx","edits":[{"find":" : reviews.reduce((sum, r) => sum + r.rating, 0) / reviews.length;","replace":" : reviews.reduce((sum) => sum + 1, 0) / reviews.length;"}]},{"id":"every-signed-in-customer-is-treated-as-an-admin","scenario":"tracks/ecommerce/scenarios/01-warehouse-admin-staff.json","targets":["ecommerce.spec.access-control.warehouse-area-boundary.7a"],"desc":"Use account presence instead of the server-provided administrator flag to expose the admin area.","file":"client/src/App.tsx","edits":[{"find":" const isAdmin = currentUser?.isAdmin ?? false;","replace":" const isAdmin = isSignedIn;"}]},{"id":"warehouse-view-omits-west","scenario":"tracks/ecommerce/scenarios/01-warehouse-admin-staff.json","targets":["ecommerce.feature.warehouse-admin.warehouse-view.7b"],"desc":"Filter one real warehouse out of the administrator's inventory view.","file":"client/src/App.tsx","edits":[{"find":" warehouses={warehouses}","replace":" warehouses={warehouses.filter((warehouse) => warehouse.name !== 'West')}"}]},{"id":"guest-purchase-falls-back-to-the-admin-account","scenario":"tracks/ecommerce/scenarios/01-purchase-session.json","targets":["ecommerce.spec.access-control.purchase-session.101a"],"desc":"Allow an unauthenticated direct purchase by attributing missing sessions to the administrator account, while preserving the authorized control path.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"export const buyNow = spacetimedb.reducer({ itemId: t.u64() }, (ctx, { itemId }) => {\n const acc = requireAccount(ctx);","replace":"export const buyNow = spacetimedb.reducer({ itemId: t.u64() }, (ctx, { itemId }) => {\n const accountId = getAccountId(ctx);\n const acc = (accountId === null ? null : ctx.db.account.id.find(accountId))\n ?? ctx.db.account.username.find('admin')!;"}]},{"id":"direct-purchases-are-attributed-to-the-system-account","scenario":"tracks/ecommerce/scenarios/01-purchase-attribution.json","targets":["ecommerce.spec.access-control.purchase-attribution.102a"],"desc":"Store every buy-now order under the administrator instead of the authenticated caller.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" accountId,\n createdAt: ctx.timestamp,\n total: Math.round(price * 100) * quantity / 100,","replace":" accountId: ctx.db.account.username.find('admin')!.id,\n createdAt: ctx.timestamp,\n total: Math.round(price * 100) * quantity / 100,"}]},{"id":"direct-restock-does-not-require-an-admin","scenario":"tracks/ecommerce/scenarios/01-admin-write-staff.json","targets":["ecommerce.spec.access-control.warehouse-write-boundary.103b"],"desc":"Remove the server-side administrator check from the restock reducer.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"export const adminRestock = spacetimedb.reducer(\n { itemId: t.u64(), warehouseId: t.u64(), quantity: t.u32() },\n (ctx, { itemId, warehouseId, quantity }) => {\n requireAdmin(ctx);","replace":"export const adminRestock = spacetimedb.reducer(\n { itemId: t.u64(), warehouseId: t.u64(), quantity: t.u32() },\n (ctx, { itemId, warehouseId, quantity }) => {\n // mutant: no administrator check"}]},{"id":"direct-purchase-ignores-the-stored-price","scenario":"tracks/ecommerce/scenarios/01-server-price.json","targets":["ecommerce.spec.transactional-integrity.server-price.104a"],"desc":"Create the direct purchase order one dollar above the authoritative stored price.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" total: Math.round(price * 100) * quantity / 100,\n status: 'pending',","replace":" total: 1,\n status: 'pending',"}]},{"id":"account-state-token-is-not-restored-after-reload","scenario":"tracks/ecommerce/scenarios/progression-account-state-reload.json","targets":["ecommerce.spec.state-durability.account-state-recovery.105a"],"desc":"Build a reload connection without the durable identity token, losing the account and its data.","file":"client/src/main.tsx","edits":[{"find":".withToken(localStorage.getItem('auth_token') || undefined)","replace":".withToken(undefined)"}]},{"id":"reconnect-discards-the-visible-account-state","scenario":"tracks/ecommerce/scenarios/progression-account-state-reconnect.json","targets":["ecommerce.spec.state-durability.account-state-recovery.105b"],"desc":"Keep normal reload recovery but discard the client account projection when the browser comes back online.","file":"client/src/App.tsx","edits":[{"find":" const currentUser = currentUserRows[0] ?? null;","replace":" const [discardAccountAfterReconnect, setDiscardAccountAfterReconnect] = useState(false);\n useEffect(() => {\n const discardAccount = () => setDiscardAccountAfterReconnect(true);\n window.addEventListener('online', discardAccount);\n return () => window.removeEventListener('online', discardAccount);\n }, []);\n const currentUser = discardAccountAfterReconnect ? null : currentUserRows[0] ?? null;"}]},{"id":"order-views-return-every-customers-orders","scenario":"tracks/ecommerce/scenarios/01-order-ownership.json","targets":["ecommerce.spec.access-control.order-ownership.106a"],"desc":"Remove account filters from both order views, exposing another customer's order and its line items.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" const rows = [...ctx.db.customerOrder.accountId.filter(accountId)];","replace":" const rows = [...ctx.db.customerOrder.iter()];"},{"find":" for (const o of ctx.db.customerOrder.accountId.filter(accountId)) {","replace":" for (const o of ctx.db.customerOrder.iter()) {"}]},{"id":"admin-revenue-double-counts-every-order","scenario":"tracks/ecommerce/scenarios/progression-books-balance.json","targets":["ecommerce.spec.transactional-integrity.books-balance.107a"],"desc":"Count every completed order twice in the administrator revenue projection.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" total += o.total - o.refundedTotal;","replace":" total += (o.total - o.refundedTotal) * 2;"}]},{"id":"purchases-do-not-leave-the-warehouses","scenario":"tracks/ecommerce/scenarios/progression-books-balance.json","targets":["ecommerce.spec.transactional-integrity.books-balance.107b"],"desc":"Create normal orders and revenue while leaving warehouse stock unchanged.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" const allocations = decrementStockTracked(ctx, itemId, quantity);","replace":" const allocations: Array<{ warehouseId: bigint; quantity: number }> = [];"}]},{"id":"review-purchase-eligibility-is-not-checked","scenario":"tracks/ecommerce/scenarios/01-review-eligibility.json","targets":["ecommerce.spec.access-control.review-eligibility.108a"],"desc":"Allow a signed-in customer to review an item with no matching purchase.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" if (!bought) throw new SenderError('You can only review items you have purchased.');","replace":" // mutant: purchase eligibility is not checked"}]},{"id":"eligible-review-is-accepted-without-being-stored","scenario":"tracks/ecommerce/scenarios/01-review-eligibility.json","targets":["ecommerce.spec.access-control.review-eligibility.108b","ecommerce.spec.access-control.review-eligibility.108a"],"desc":"Keep the non-buyer refusal but omit the insert for a buyer's eligible new review. Both eligibility criteria require a successfully stored eligible review as a positive control; this does not establish a non-buyer authorization defect.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" ctx.db.review.insert({\n id: 0n,\n itemId,\n accountId: acc.id,\n rating,\n comment,\n createdAt: ctx.timestamp,\n });","replace":" // mutant: eligible review is acknowledged but not persisted"}]},{"id":"cart-line-lookup-ignores-cart-ownership","scenario":"tracks/ecommerce/scenarios/01-cart-boundary.json","targets":["ecommerce.spec.access-control.cart-boundary.109a"],"desc":"Find an existing cart line by item alone, so the same named add action from another customer increments the owner's line instead of that customer's cart.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"function findCartLine(ctx: Ctx, accountId: bigint, itemId: bigint) {\n for (const row of ctx.db.cartItem.byAccountItem.filter([accountId, itemId])) {\n return row;\n }\n return null;\n}","replace":"function findCartLine(ctx: Ctx, _accountId: bigint, itemId: bigint) {\n for (const row of ctx.db.cartItem.iter()) {\n if (row.itemId === itemId) return row;\n }\n return null;\n}"}]},{"id":"purchase-does-not-reserve-stock-last-unit","scenario":"tracks/ecommerce/scenarios/01-last-unit.json","targets":["ecommerce.spec.concurrency-safety.last-unit.201a","ecommerce.spec.concurrency-safety.last-unit.201b","ecommerce.spec.concurrency-safety.last-unit.201c"],"desc":"Create purchase orders without reserving stock, proving the focused last-unit stock, order-count, and revenue consequences.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" const allocations = decrementStockTracked(ctx, itemId, quantity);","replace":" const allocations: Array<{ warehouseId: bigint; quantity: number }> = [];"}]},{"id":"existing-cart-line-does-not-increment","scenario":"tracks/ecommerce/scenarios/01-duplicate-checkout.json","targets":["ecommerce.spec.concurrency-safety.duplicate-checkout.203a"],"desc":"Render the old cart quantity after concurrent adds.","file":"client/src/components/CartPanel.tsx","edits":[{"find":" value={line.quantity}","replace":" value={1}"}]},{"id":"checkout-does-not-empty-cart","scenario":"tracks/ecommerce/scenarios/01-duplicate-checkout.json","targets":["ecommerce.spec.concurrency-safety.duplicate-checkout.203b"],"desc":"Keep checked-out cart lines so the next serialized checkout creates a duplicate order.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" for (const line of lines) ctx.db.cartItem.id.delete(line.id);","replace":" // mutant: checked-out lines remain in the cart"}]},{"id":"stock-subscription-snapshotted-once","scenario":"tracks/ecommerce/scenarios/01-external-live-sync.json","targets":["ecommerce.spec.external-data-sync.external-stock.901a"],"desc":"Render the first non-empty stock snapshot forever instead of following committed subscription updates.","file":"client/src/App.tsx","edits":[{"find":"import { useEffect, useMemo, useState } from 'react';","replace":"import { useEffect, useMemo, useRef, useState } from 'react';"},{"find":" const [stocks] = useTable(tables.stock);","replace":" const [liveStocks] = useTable(tables.stock);\n const initialStocks = useRef(null);\n if (initialStocks.current === null && liveStocks.length > 0) {\n initialStocks.current = liveStocks;\n }\n const stocks = initialStocks.current ?? liveStocks;"}]},{"id":"stock-view-ignores-update-across-app-server-stop","scenario":"tracks/ecommerce/scenarios/01-external-server-restart-sync.json","targets":["ecommerce.spec.external-data-sync.external-stock.901c"],"desc":"Persist the first stock quantities in browser session storage and keep rendering them after app-server restart, including any frontend reload. Initial stock remains correct. This validates the stale-view oracle, not SpacetimeDB storage durability.","file":"client/src/App.tsx","edits":[{"find":" const [stocks] = useTable(tables.stock);","replace":" const [liveStocks] = useTable(tables.stock);\n const cacheKey = 'stale-stock-quantities';\n let savedQuantities = sessionStorage.getItem(cacheKey);\n if (!savedQuantities && liveStocks.length > 0) {\n savedQuantities = JSON.stringify(Object.fromEntries(liveStocks.map(row => [`${row.itemId}-${row.warehouseId}`, row.quantity])));\n sessionStorage.setItem(cacheKey, savedQuantities);\n }\n const quantities: Record = JSON.parse(savedQuantities ?? '{}');\n const stocks = liveStocks.map(row => ({ ...row, quantity: quantities[`${row.itemId}-${row.warehouseId}`] ?? row.quantity }));"}]},{"id":"stock-view-keeps-pre-reconnect-snapshot","scenario":"tracks/ecommerce/scenarios/01-external-reconnect-sync.json","targets":["ecommerce.spec.external-data-sync.external-stock.901d"],"desc":"Continue following stock until the browser goes offline, then retain the last online snapshot after network restoration.","file":"client/src/App.tsx","edits":[{"find":"import { useEffect, useMemo, useState } from 'react';","replace":"import { useEffect, useMemo, useRef, useState } from 'react';"},{"find":" const [stocks] = useTable(tables.stock);","replace":" const [liveStocks] = useTable(tables.stock);\n const [freezeStockAfterOffline, setFreezeStockAfterOffline] = useState(false);\n const lastOnlineStocks = useRef(liveStocks);\n useEffect(() => {\n const freezeStock = () => setFreezeStockAfterOffline(true);\n window.addEventListener('offline', freezeStock);\n return () => window.removeEventListener('offline', freezeStock);\n }, []);\n if (!freezeStockAfterOffline) {\n lastOnlineStocks.current = liveStocks;\n }\n const stocks = freezeStockAfterOffline ? lastOnlineStocks.current : liveStocks;"}]},{"id":"open-review-list-snapshots-on-selection","scenario":"tracks/ecommerce/scenarios/progression-open-list-live.json","targets":["ecommerce.spec.live-state.open-list.902a"],"desc":"Snapshot the selected item's reviews when the detail opens instead of following later subscription updates.","file":"client/src/App.tsx","edits":[{"find":"import { useEffect, useMemo, useState } from 'react';","replace":"import { useEffect, useMemo, useRef, useState } from 'react';"},{"find":" const selectedItemReviews = selectedItemId !== null ? reviewsByItem.get(selectedItemId) ?? [] : [];","replace":" const openedReviewItem = useRef(null);\n const openedReviews = useRef<(typeof reviews)[number][]>([]);\n if (selectedItemId !== openedReviewItem.current) {\n openedReviewItem.current = selectedItemId;\n openedReviews.current = selectedItemId !== null ? reviewsByItem.get(selectedItemId) ?? [] : [];\n }\n const selectedItemReviews = openedReviews.current;"}]},{"id":"open-review-list-renders-each-review-twice","scenario":"tracks/ecommerce/scenarios/progression-open-list-live.json","targets":["ecommerce.spec.live-state.open-list.902a"],"desc":"Render every committed review twice in the already-open list.","file":"client/src/components/ItemDetail.tsx","edits":[{"find":" {reviews.map((r) => (","replace":" {[...reviews, ...reviews].map((r) => ("}]},{"id":"cancel-does-not-restore-stock-feature","scenario":"tracks/ecommerce/scenarios/02-order-cancellation-core.json","targets":["ecommerce.returns-pricing.cancellation-and-return.3a"],"desc":"The serialized cancellation reducer changes order state and purchase counts but skips allocation restoration.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" restoreOrderItemStock(ctx, li);\n decrementPurchaseCount(ctx, li.itemId, li.quantity);","replace":" // mutant: cancellation does not restore its reserved stock\n decrementPurchaseCount(ctx, li.itemId, li.quantity);"}]},{"id":"cancellation-accounting-loses-stock-restoration","scenario":"tracks/ecommerce/scenarios/02-invariants.json","targets":["ecommerce.returns-pricing.refund-accounting.203a"],"desc":"Cancellation removes revenue and changes order status, but loses the original warehouse stock restoration. The native refund-accounting assertion must detect this.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" restoreOrderItemStock(ctx, li);\n decrementPurchaseCount(ctx, li.itemId, li.quantity);","replace":" // mutant: cancellation does not restore its reserved stock\n decrementPurchaseCount(ctx, li.itemId, li.quantity);"}]},{"id":"cancel-does-not-restore-stock-fresh-client","scenario":"tracks/ecommerce/scenarios/02-self-contained.json","targets":["ecommerce.inventory-operations.stock-conservation.202b","ecommerce.inventory-operations.stock-conservation.202c"],"desc":"The serialized cancellation reducer skips allocation restoration, so a fresh client reads the persisted shortfall.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" restoreOrderItemStock(ctx, li);\n decrementPurchaseCount(ctx, li.itemId, li.quantity);","replace":" // mutant: cancellation does not restore its reserved stock\n decrementPurchaseCount(ctx, li.itemId, li.quantity);"}]},{"id":"cancel-restores-stock-but-keeps-pending-status","scenario":"tracks/ecommerce/scenarios/02-order-cancellation-history.json","targets":["ecommerce.returns-pricing.cancellation-and-return.3b"],"desc":"The serialized cancellation reducer restores allocations but writes pending back to order history.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" ctx.db.customerOrder.id.update({ ...order, status: 'cancelled' });","replace":" ctx.db.customerOrder.id.update({ ...order, status: 'pending' });"}]},{"id":"cancelled-order-remains-in-revenue-feature","scenario":"tracks/ecommerce/scenarios/02-order-cancellation-core.json","targets":["ecommerce.returns-pricing.cancellation-and-return.3a"],"desc":"The admin revenue view includes cancelled orders even though cancellation otherwise succeeds.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" if (!isOrderCounted(o)) continue;\n total += o.total - o.refundedTotal;","replace":" total += o.total - o.refundedTotal;"}]},{"id":"cancelled-order-remains-in-revenue-invariant","scenario":"tracks/ecommerce/scenarios/02-invariants.json","targets":["ecommerce.returns-pricing.refund-accounting.203a"],"desc":"The admin revenue view includes cancelled orders even though cancellation otherwise succeeds.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" if (!isOrderCounted(o)) continue;\n total += o.total - o.refundedTotal;","replace":" total += o.total - o.refundedTotal;"}]},{"id":"operator-authorization-allows-customer-transfer","scenario":"tracks/ecommerce/scenarios/02-strengthened.json","targets":["ecommerce.operations-access.operator-authorization.201a"],"desc":"The transfer reducer drops its administrator role gate.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" (ctx, { itemId, fromWarehouseId, toWarehouseId, quantity }) => {\n requireAdmin(ctx);","replace":" (ctx, { itemId, fromWarehouseId, toWarehouseId, quantity }) => {\n // mutant: no administrator role check"}]},{"id":"customer-can-ship-order-direct-1-1","scenario":"tracks/ecommerce/scenarios/02-server-actions.json","targets":["ecommerce.operations-access.operator-authorization.201c"],"desc":"The shipping reducer drops its staff role check while retaining pending-state validation.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"export const shipOrder = spacetimedb.reducer({ orderId: t.u64() }, (ctx, { orderId }) => {\n requireStaffOrAdmin(ctx);","replace":"export const shipOrder = spacetimedb.reducer({ orderId: t.u64() }, (ctx, { orderId }) => {\n // mutant: no staff role check"}]},{"id":"customer-can-cancel-foreign-order-1-1","scenario":"tracks/ecommerce/scenarios/02-server-actions.json","targets":["ecommerce.operations-access.order-owner.204a"],"desc":"Cancellation bypasses the owner helper while retaining missing-order and pending-state validation.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"export const cancelOrder = spacetimedb.reducer({ orderId: t.u64() }, (ctx, { orderId }) => {\n const order = requireOrderOwner(ctx, orderId);","replace":"export const cancelOrder = spacetimedb.reducer({ orderId: t.u64() }, (ctx, { orderId }) => {\n const order = ctx.db.customerOrder.id.find(orderId);\n if (!order) throw new SenderError('Order not found.');"}]},{"id":"queue-depth-lags-one-order","scenario":"tracks/ecommerce/scenarios/02-fulfilment-live.json","targets":["ecommerce.operations-access.fulfilment-queue.1a"],"desc":"The reactive queue renders every order but its visible depth remains one behind.","file":"client/src/components/FulfilmentPanel.tsx","edits":[{"find":"Waiting: {queue.length}","replace":"Waiting: {Math.max(0, queue.length - 1)}"}]},{"id":"ship-acknowledges-without-changing-status","scenario":"tracks/ecommerce/scenarios/02-fulfilment-ship.json","targets":["ecommerce.operations-access.fulfilment-queue.1c"],"desc":"The serialized shipping reducer accepts the call but writes pending back to the order.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" ctx.db.customerOrder.id.update({ ...order, status: 'shipped' });","replace":" ctx.db.customerOrder.id.update({ ...order, status: 'pending' });"}]},{"id":"customer-sees-fulfilment-navigation","scenario":"tracks/ecommerce/scenarios/02-features.json","targets":["ecommerce.operations-access.fulfilment-queue.1d"],"desc":"Expose the protected staff area to signed-in customers, including its navigation and content.","file":"client/src/App.tsx","edits":[{"find":" const isStaff = currentUser?.isStaff ?? false;","replace":" const isStaff = isSignedIn;"}]},{"id":"progression-customer-sees-fulfilment-content","scenario":"tracks/ecommerce/scenarios/02-fulfilment-access.json","targets":["ecommerce.spec.access-control.fulfilment-area-boundary.1d"],"desc":"Expose the protected staff area to signed-in customers, including its navigation and content.","file":"client/src/App.tsx","edits":[{"find":" const isStaff = currentUser?.isStaff ?? false;","replace":" const isStaff = isSignedIn;"}]},{"id":"operator-authorization-allows-customer-shipping","scenario":"tracks/ecommerce/scenarios/02-server-actions.json","targets":["ecommerce.operations-access.operator-authorization.201c"],"desc":"The shipping reducer drops the staff role check while retaining the pending-order guard.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"export const shipOrder = spacetimedb.reducer({ orderId: t.u64() }, (ctx, { orderId }) => {\n requireStaffOrAdmin(ctx);","replace":"export const shipOrder = spacetimedb.reducer({ orderId: t.u64() }, (ctx, { orderId }) => {\n // mutant: no staff role check"}]},{"id":"transfer-debits-source-without-crediting-existing-destination","scenario":"tracks/ecommerce/scenarios/02-strengthened.json","targets":["ecommerce.inventory-operations.stock-conservation.202a","ecommerce.inventory-operations.warehouse-transfer.2a","ecommerce.operations-access.operator-authorization.201a"],"desc":"A transfer debits the source row but writes the existing destination quantity back unchanged, violating both directional movement and total conservation inside the serialized reducer. It also breaks 201a's authorized-transfer positive control; that coupled failure is not independent evidence of an authorization defect.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" ctx.db.stock.insert({ ...toRow, quantity: toRow.quantity + quantity });","replace":" ctx.db.stock.insert({ ...toRow, quantity: toRow.quantity });"}]},{"id":"transfer-warehouse-totals-omit-destination-credit","scenario":"tracks/ecommerce/scenarios/02-transfer-totals.json","targets":["ecommerce.inventory-operations.warehouse-transfer.2b"],"desc":"The serialized transfer debits the source but writes the existing destination quantity back unchanged.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" ctx.db.stock.insert({ ...toRow, quantity: toRow.quantity + quantity });","replace":" ctx.db.stock.insert({ ...toRow, quantity: toRow.quantity });"}]},{"id":"transfer-overdraft-guard-removed","scenario":"tracks/ecommerce/scenarios/02-transfer-overdraw.json","targets":["ecommerce.inventory-operations.warehouse-transfer.2c"],"desc":"The serialized reducer no longer rejects insufficient source stock and commits negative source quantity.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" if (available < quantity) {\n throw new SenderError(`Not enough stock in source warehouse: only ${available} available.`);\n }","replace":" // mutant: insufficient source stock is not rejected"}]},{"id":"low-stock-excludes-boundary-ten","scenario":"tracks/ecommerce/scenarios/02-low-stock.json","targets":["ecommerce.inventory-operations.operational-views.5a"],"desc":"The reactive low-stock view uses a strict boundary and omits items with exactly ten units.","file":"client/src/App.tsx","edits":[{"find":" .filter((i) => (stockByItem.get(i.id) ?? 0) <= LOW_STOCK_THRESHOLD)","replace":" .filter((i) => (stockByItem.get(i.id) ?? 0) < LOW_STOCK_THRESHOLD)"}]},{"id":"category-totals-ignore-pending-purchases","scenario":"tracks/ecommerce/scenarios/02-operational-category-totals.json","targets":["ecommerce.inventory-operations.operational-views.5b"],"desc":"The category totals view includes only shipped orders, so a newly accepted pending purchase is absent.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" for (const order of ctx.db.customerOrder.iter()) {\n if (!isOrderCounted(order)) continue;","replace":" for (const order of ctx.db.customerOrder.iter()) {\n if (order.status !== 'shipped') continue;"}]},{"id":"recommendations-ignore-pending-purchases","scenario":"tracks/ecommerce/scenarios/02-operational-recommendations.json","targets":["ecommerce.inventory-operations.operational-views.5c"],"desc":"The personal recommendation view derives categories only from shipped orders, so a new pending purchase has no influence.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" for (const order of ctx.db.customerOrder.accountId.filter(accountId)) {\n if (!isOrderCounted(order)) continue;","replace":" for (const order of ctx.db.customerOrder.accountId.filter(accountId)) {\n if (order.status !== 'shipped') continue;"}]},{"id":"purchases-do-not-affect-best-sellers","scenario":"tracks/ecommerce/scenarios/02-operational-best-sellers.json","targets":["ecommerce.inventory-operations.operational-views.5d"],"desc":"Rank signed-out recommendations without purchase counts.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"const purchaseCountOf = (id: bigint) => ctx.db.itemStats.itemId.find(id)?.purchaseCount ?? 0;","replace":"const purchaseCountOf = (_id: bigint) => 0;"}]},{"id":"queue-warehouse-reports-west","scenario":"tracks/ecommerce/scenarios/02-queue-warehouse.json","targets":["ecommerce.operations-access.fulfilment-queue.1b"],"desc":"The queue renders West for the deterministic Desk Lamp allocation even though the order reserved stock in East.","file":"client/src/components/FulfilmentPanel.tsx","edits":[{"find":"{name}: {order.warehouseNames[i]}","replace":"{name}: West"}]},{"id":"transfer-creates-stock-during-race","scenario":"tracks/ecommerce/scenarios/02-server-actions.json","targets":["ecommerce.inventory-operations.stock-conservation.202d"],"desc":"The transfer reducer credits the destination one unit more than it debits from the source, so the item's total after a transfer racing a purchase is the starting total rather than one less. A stored conservation defect; it does not model a lost-update interleaving because SpacetimeDB reducer execution is atomically serialized.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" ctx.db.stock.insert({ ...toRow, quantity: toRow.quantity + quantity });","replace":" ctx.db.stock.insert({ ...toRow, quantity: toRow.quantity + quantity + 1 });"}]},{"id":"catalog-search-ignores-the-query","scenario":"tracks/ecommerce/scenarios/01-catalog-search.json","targets":["ecommerce.feature.catalog.catalog-search.2d"],"desc":"A non-empty catalog query filters out every product instead of matching names.","file":"client/src/App.tsx","edits":[{"find":".filter(item => !q || item.name.toLowerCase().includes(q))","replace":".filter(() => !q) // mutant: non-empty searches return no products"}]},{"id":"admin-total-stock-is-not-rendered","scenario":"tracks/ecommerce/scenarios/01-warehouse-stock-live-staff.json","targets":["ecommerce.spec.live-state.warehouse-stock.7c"],"desc":"The staff stock total always renders zero after a warehouse restock.","file":"client/src/components/AdminPanel.tsx","edits":[{"find":"{totalStockOf(item.id)}","replace":"{0}"}]},{"id":"customers-can-schedule-restocks","scenario":"tracks/ecommerce/scenarios/03-deferred-access.json","targets":["ecommerce.l3.deferred-access.scheduled-work-access.317a"],"desc":"Scheduling a restock no longer checks that the caller is an administrator.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" (ctx, input) => {\n requireAdmin(ctx);\n const itemName = input.item.trim();\n const warehouseName = input.warehouse.trim();\n const item = [...ctx.db.item].find(row => row.name === itemName);\n const warehouse = [...ctx.db.warehouse].find(row => row.name === warehouseName);","replace":" (ctx, input) => {\n // mutant: any signed-in or anonymous caller can schedule work\n const itemName = input.item.trim();\n const warehouseName = input.warehouse.trim();\n const item = [...ctx.db.item].find(row => row.name === itemName);\n const warehouse = [...ctx.db.warehouse].find(row => row.name === warehouseName);"}]},{"id":"scheduled-restock-execution-queue-is-process-local","scenario":"tracks/ecommerce/scenarios/03-deferred-durability.json","targets":["ecommerce.l3.deferred-durability.restart-survival.311a"],"desc":"Keep manual restock execution IDs only in the V8 process. Ordinary timers work, but restart loses the execution queue while pending rows remain. Isolate replacement can also lose this queue.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"export const scheduleRestock = spacetimedb.reducer(","replace":"const pendingRestockExecution = new Set();\n\nexport const scheduleRestock = spacetimedb.reducer("},{"find":" ctx.db.scheduledRestock.insert({\n id: 0n,\n itemId: item.id,\n warehouseId: warehouse.id,\n quantity: input.quantity,\n dueMicros: nowMicros(ctx) + BigInt(input.delaySeconds) * SECOND,\n status: 'pending',\n reorderRuleId: undefined,\n });","replace":" const pending = ctx.db.scheduledRestock.insert({\n id: 0n,\n itemId: item.id,\n warehouseId: warehouse.id,\n quantity: input.quantity,\n dueMicros: nowMicros(ctx) + BigInt(input.delaySeconds) * SECOND,\n status: 'pending',\n reorderRuleId: undefined,\n });\n pendingRestockExecution.add(pending.id);"},{"find":" if (pending.status !== 'pending' || pending.dueMicros > now) continue;\n restoreStock(ctx, pending.itemId, pending.warehouseId, pending.quantity);","replace":" if (pending.status !== 'pending' || pending.dueMicros > now) continue;\n if (pending.reorderRuleId === undefined && !pendingRestockExecution.delete(pending.id)) continue;\n restoreStock(ctx, pending.itemId, pending.warehouseId, pending.quantity);"}]},{"id":"reservation-is-delayed-past-the-durability-window","scenario":"tracks/ecommerce/scenarios/03-deferred-durability.json","targets":["ecommerce.l3.deferred-durability.restart-survival.314a"],"desc":"A reservation is persisted with a ten-minute lifetime instead of ninety seconds.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"const expiresMicros = nowMicros(ctx) + 90n * SECOND;","replace":"const expiresMicros = nowMicros(ctx) + 600n * SECOND;"}]},{"id":"completed-restock-remains-pending","scenario":"tracks/ecommerce/scenarios/03-deferred-integrity.json","targets":["ecommerce.l3.deferred-integrity.exactly-once.311a"],"desc":"A completed restock remains pending and is applied again by later maintenance ticks.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"ctx.db.scheduledRestock.id.update({ ...pending, status: 'complete' });","replace":"ctx.db.scheduledRestock.id.update({ ...pending, status: 'pending' });"}]},{"id":"reservation-expiry-restores-stock-twice","scenario":"tracks/ecommerce/scenarios/03-deferred-integrity.json","targets":["ecommerce.l3.deferred-integrity.stock-conservation.313a"],"desc":"Reservation expiry returns twice the quantity that was reserved.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"restoreStock(ctx, row.stockItemId || row.itemId, row.warehouseId, row.quantity);\n ctx.db.reservation.id.update({ ...row, expired: true });","replace":"restoreStock(ctx, row.stockItemId || row.itemId, row.warehouseId, row.quantity * 2);\n ctx.db.reservation.id.update({ ...row, expired: true });"}]},{"id":"checkout-takes-reserved-stock-again","scenario":"tracks/ecommerce/scenarios/03-deferred-integrity.json","targets":["ecommerce.l3.deferred-integrity.stock-conservation.314a"],"desc":"Checkout decrements stock after the cart reservation already took it.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"const allocations = held.map(row => ({ warehouseId: row.warehouseId, quantity: row.quantity, stockItemId: row.stockItemId }));\n const orderItemRow","replace":"const allocations = decrementStockTracked(ctx, p.itemId, p.quantity);\n const orderItemRow"}]},{"id":"reservation-does-not-decrement-stock","scenario":"tracks/ecommerce/scenarios/03-reservations.json","targets":["ecommerce.l3.reservations.reservations.301a"],"desc":"Creating a reservation leaves the public stock total unchanged.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"ctx.db.stock.insert({ ...row, quantity: row.quantity - allocation.quantity });","replace":"ctx.db.stock.insert({ ...row, quantity: row.quantity });"}]},{"id":"reservation-timer-is-static","scenario":"tracks/ecommerce/scenarios/03-reservations.json","targets":["ecommerce.l3.reservations.reservations.305a"],"desc":"The cart always renders ninety seconds instead of a decreasing reservation timer.","file":"client/src/components/CartPanel.tsx","edits":[{"find":"const seconds = Math.max(0, Number((reservation.expiresMicros - BigInt(Date.now()) * 1000n) / 1_000_000n));","replace":"const seconds = 90;"}]},{"id":"checkout-leaves-cart-lines","scenario":"tracks/ecommerce/scenarios/03-reservations.json","targets":["ecommerce.l3.reservations.reservations.306a"],"desc":"Checkout creates an order but leaves the purchased lines in the cart.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"for (const line of lines) ctx.db.cartItem.id.delete(line.id);","replace":"for (const line of lines) void line;"}]},{"id":"expired-reservation-is-still-marked-live","scenario":"tracks/ecommerce/scenarios/03-reservations.json","targets":["ecommerce.l3.reservations.reservations.307a"],"desc":"Expired reservations keep their live flag, so the cart does not mark them expired.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"ctx.db.reservation.id.update({ ...row, expired: true });","replace":"ctx.db.reservation.id.update({ ...row, expired: false });"}]},{"id":"renewed-reservation-expires-too-soon","scenario":"tracks/ecommerce/scenarios/03-reservations.json","targets":["ecommerce.l3.reservations.reservations.308a"],"desc":"Renewed quantities receive only a twenty-second reservation window.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"reserveUnits(ctx, accountId, itemId, quantity);","replace":"reserveUnits(ctx, accountId, itemId, quantity);\n for (const renewed of findReservations(ctx, accountId, itemId)) {\n ctx.db.reservation.id.update({ ...renewed, expiresMicros: nowMicros(ctx) + 20n * SECOND });\n }"}]},{"id":"pending-restock-timer-is-static","scenario":"tracks/ecommerce/scenarios/03-scheduled-restocks.json","targets":["ecommerce.l3.scheduled-restocks.scheduled-restocks.302a"],"desc":"The pending restock UI always renders ninety seconds instead of the server due time.","file":"client/src/components/ProgressionWorkbench.tsx","edits":[{"find":"{Math.max(0, Number((row.dueMicros - BigInt(Date.now()) * 1000n) / 1_000_000n))}","replace":"{90}"}]},{"id":"due-restock-omits-ledger-entry","scenario":"tracks/ecommerce/scenarios/03-scheduled-restock-apply.json","targets":["ecommerce.l3.scheduled-restocks.scheduled-restocks.305a"],"desc":"A due restock updates stock but does not create its stock ledger record.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"ctx.db.stockLedger.insert({\n id: 0n,\n itemId: pending.itemId,\n warehouseId: pending.warehouseId,\n quantity: pending.quantity,\n createdMicros: now,\n source: 'scheduled restock',\n });","replace":"// mutant: due restocks are not recorded in the ledger"}]},{"id":"cancelled-restock-remains-pending","scenario":"tracks/ecommerce/scenarios/03-scheduled-restock-cancel.json","targets":["ecommerce.l3.scheduled-restocks.scheduled-restocks.306a"],"desc":"Cancelling a restock leaves it pending, so maintenance later applies it.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"ctx.db.scheduledRestock.id.update({ ...row, status: 'cancelled' });","replace":"ctx.db.scheduledRestock.id.update({ ...row, status: 'pending' });"}]},{"id":"restart-restock-runs-early","scenario":"tracks/ecommerce/scenarios/03-server-time.json","targets":["ecommerce.l3.server-time.server-time.312a"],"desc":"A scheduled restock ignores its requested delay and becomes due after one second.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"dueMicros: nowMicros(ctx) + BigInt(input.delaySeconds) * SECOND,","replace":"dueMicros: nowMicros(ctx) + SECOND,"}]},{"id":"closed-browser-reservation-never-expires","scenario":"tracks/ecommerce/scenarios/03-server-time.json","targets":["ecommerce.l3.server-time.server-time.313a"],"desc":"Server maintenance skips reservation expiry when no customer browser is present.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"for (const row of [...ctx.db.reservation.iter()]) {\n if (row.expired || row.expiresMicros > now) continue;","replace":"for (const row of [...ctx.db.reservation.iter()].filter(() => false)) {\n if (row.expired || row.expiresMicros > now) continue;"}]},{"id":"catalog-product-is-not-published","scenario":"tracks/ecommerce/scenarios/progression-catalog-management.json","targets":["ecommerce.progression.catalog-management.catalog-management.622a","ecommerce.progression.catalog-management.catalog-management.622b"],"desc":"The public product card omits the submitted name. Both create visibility and variant navigation locate the submitted product card by its name, so the hidden name prevents both required observations.","file":"client/src/components/ItemCard.tsx","edits":[{"find":"{item.name}","replace":"{item.name === 'Travel Mug' ? '' : item.name}"}]},{"id":"catalog-variants-are-discarded","scenario":"tracks/ecommerce/scenarios/progression-catalog-management.json","targets":["ecommerce.progression.catalog-management.catalog-management.622b"],"desc":"Catalog management discards every submitted product variant.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"for (const variantName of variants.split(',').map(value => value.trim()).filter(Boolean)) {\n ctx.db.itemVariant.insert({ id: 0n, itemId: product.id, name: variantName });\n }","replace":"void variants; // mutant: submitted variants are discarded"}]},{"id":"profile-is-lost-on-fresh-account-login","scenario":"tracks/ecommerce/scenarios/progression-customer-profile.json","targets":["ecommerce.spec.state-durability.customer-profile-reload.620a"],"desc":"Delete a saved profile when its owner signs in from a new transport identity. Initial save, same-identity reload, and the independent privacy owner remain intact.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" throw new SenderError('Incorrect username or password.');\n }\n\n const existingSession = ctx.db.session.identity.find(ctx.sender);\n if (existingSession) {\n ctx.db.session.identity.update({ ...existingSession, accountId: acc.id });","replace":" throw new SenderError('Incorrect username or password.');\n }\n\n const existingSession = ctx.db.session.identity.find(ctx.sender);\n if (!existingSession) { ctx.db.customerProfile.accountId.delete(acc.id); }\n if (existingSession) {\n ctx.db.session.identity.update({ ...existingSession, accountId: acc.id });"}]},{"id":"customer-profile-view-leaks-another-account","scenario":"tracks/ecommerce/scenarios/progression-customer-profile.json","targets":["ecommerce.spec.access-control.customer-profile-privacy.620b"],"desc":"The customer profile view returns the first stored profile without checking its owner.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"return accountId === null ? undefined : ctx.db.customerProfile.accountId.find(accountId) ?? undefined;","replace":"return accountId === null ? undefined : [...ctx.db.customerProfile.iter()][0];"}]},{"id":"faceted-search-ignores-category","scenario":"tracks/ecommerce/scenarios/progression-faceted-filters.json","targets":["ecommerce.progression.faceted-search.faceted-search.401a"],"desc":"Faceted search applies price and stock filters but ignores the selected category.","file":"client/src/App.tsx","edits":[{"find":".filter(item => !categoryFilter || categoryByItem.get(item.id) === categoryFilter)","replace":".filter(() => true) // mutant: category filter is ignored"}]},{"id":"active-search-uses-purchase-ranking","scenario":"tracks/ecommerce/scenarios/progression-search-ordering.json","targets":["ecommerce.spec.search-ordering.search-ordering.402b"],"desc":"Keep purchase ranking when search text or filters are active.","file":"client/src/App.tsx","edits":[{"find":"const catalogItems = showingSearch ? filteredSearchResults : rankedItems;","replace":"const catalogItems = rankedItems;"}]},{"id":"faceted-search-next-page-does-not-advance","scenario":"tracks/ecommerce/scenarios/progression-faceted-pagination.json","targets":["ecommerce.progression.faceted-search.faceted-search.402a"],"desc":"The next-page control keeps the search on its current page.","file":"client/src/App.tsx","edits":[{"find":"onClick={() => setSearchPage(page => page + 1)}>Next","replace":"onClick={() => setSearchPage(page => page)}>Next"}]},{"id":"managed-support-leaks-and-accepts-cross-account-replies","scenario":"tracks/ecommerce/scenarios/progression-managed-support-privacy.json","targets":["ecommerce.spec.access-control.managed-support-privacy.613b"],"desc":"Managed support tickets are visible across accounts and replayed replies are accepted.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":".filter(row => isGuestTicketCreator(sender, row.creatorIdentity.toHexString(), row.accountId) ||\n !!actor && (actor.isAdmin || actor.isStaff || row.accountId === accountId))","replace":".filter(() => true)"},{"file":"backend/spacetimedb/src/index.ts","find":"if (!actor.isAdmin && !actor.isStaff && ticket.accountId !== actor.id) {\n throw new SenderError('That support ticket is private.');\n }","replace":"// mutant: any signed-in account can access any support ticket"}]},{"id":"managed-support-replies-are-empty","scenario":"tracks/ecommerce/scenarios/progression-managed-support-shared.json","targets":["ecommerce.spec.live-state.managed-support.613a","ecommerce.progression.managed-support.managed-support.613c"],"desc":"Managed support stores replies without their message body. Both the ordinary reply and shared-live reply assertions require the stored message body; neither can pass an empty reply.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"body: body.trim(),\n createdMicros: nowMicros(ctx),","replace":"body: '',\n createdMicros: nowMicros(ctx),"}]},{"id":"managed-support-live-replies-stay-at-initial-snapshot","scenario":"tracks/ecommerce/scenarios/progression-managed-support-shared.json","targets":["ecommerce.spec.live-state.managed-support.613a"],"desc":"Keep the initial subscribed reply snapshot on each page. Reducers still save replies, and a reload shows them, but later replies do not reach the rendered conversation live.","file":"client/src/App.tsx","edits":[{"find":" const [supportReplyRows] = useTable(tables.visibleSupportReplies);","replace":" const [liveSupportReplyRows, supportRepliesReady] = useTable(tables.visibleSupportReplies);\n const supportReplyRows = useMemo(() => [...liveSupportReplyRows], [supportRepliesReady]);"}]},{"id":"notification-preferences-are-not-saved","scenario":"tracks/ecommerce/scenarios/progression-notification-preferences.json","targets":["ecommerce.spec.state-durability.notification-preferences-reload.630a"],"desc":"Saving notification preferences discards the selected values.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"if (existing) ctx.db.notificationPreference.accountId.update(row);\n else ctx.db.notificationPreference.insert(row);","replace":"void existing;\n void row; // mutant: notification preferences are discarded"}]},{"id":"notification-preferences-leak-across-accounts","scenario":"tracks/ecommerce/scenarios/progression-notification-preferences.json","targets":["ecommerce.spec.access-control.notification-preferences-privacy.630b"],"desc":"The preference view returns another account's first stored choice.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"const row = ctx.db.notificationPreference.accountId.find(accountId);\n return row ? { orderEnabled: row.orderEnabled, stockEnabled: row.stockEnabled } : undefined;","replace":"const row = [...ctx.db.notificationPreference.iter()][0];\n return row ? { orderEnabled: row.orderEnabled, stockEnabled: row.stockEnabled } : undefined;"}]},{"id":"checkout-records-zero-payment","scenario":"tracks/ecommerce/scenarios/progression-core-business.json","targets":["ecommerce.progression.payment-records.payment-records.623a"],"desc":"Checkout records a paid payment with a zero amount.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"ctx.db.paymentRecord.insert({ id: 0n, orderId: order.id, amount: order.total, status: 'paid' });\n if (promo) {","replace":"ctx.db.paymentRecord.insert({ id: 0n, orderId: order.id, amount: 0, status: 'paid' });\n if (promo) {"}]},{"id":"checkout-records-duplicate-payments","scenario":"tracks/ecommerce/scenarios/progression-core-business.json","targets":["ecommerce.spec.transactional-integrity.payment-deduplication.623b"],"desc":"Checkout inserts two payment records for one order.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"ctx.db.paymentRecord.insert({ id: 0n, orderId: order.id, amount: order.total, status: 'paid' });\n if (promo) {","replace":"ctx.db.paymentRecord.insert({ id: 0n, orderId: order.id, amount: order.total, status: 'paid' });\n ctx.db.paymentRecord.insert({ id: 0n, orderId: order.id, amount: order.total + 0.01, status: 'paid' });\n if (promo) {"}]},{"id":"active-promotion-does-not-discount-checkout","scenario":"tracks/ecommerce/scenarios/progression-promotion-checkout.json","targets":["ecommerce.progression.promotion-checkout.promotion-checkout-active.621a"],"desc":"Checkout ignores an active promotion when it calculates the discount.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"const discount = promo ? total * (promo.discountPercent / 100) : 0;","replace":"const discount = 0;"}]},{"id":"expired-promotion-is-accepted","scenario":"tracks/ecommerce/scenarios/progression-promotion-checkout.json","targets":["ecommerce.progression.promotion-checkout.promotion-checkout-expired.621b"],"desc":"Promotion application does not reject a promotion after its end time.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"if (!promo || promo.startMicros > now || promo.endMicros < now || promo.redemptions >= promo.usageLimit) {","replace":"if (!promo || promo.startMicros > now || promo.redemptions >= promo.usageLimit) {"}]},{"id":"exhausted-promotion-is-accepted","scenario":"tracks/ecommerce/scenarios/progression-promotion-checkout.json","targets":["ecommerce.progression.promotion-checkout.promotion-checkout-exhausted.621c"],"desc":"Promotion application does not reject a promotion at its usage limit.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"if (!promo || promo.startMicros > now || promo.endMicros < now || promo.redemptions >= promo.usageLimit) {","replace":"if (!promo || promo.startMicros > now || promo.endMicros < now) {"}]},{"id":"customers-can-create-promotions","scenario":"tracks/ecommerce/scenarios/progression-promotion-rules.json","targets":["ecommerce.spec.access-control.promotion-management-boundary.620b"],"desc":"Promotion creation does not require staff access.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" (ctx, input) => {\n requireStaffOrAdmin(ctx);\n if (input.discountPercent <= 0 || input.discountPercent > 100) {","replace":" (ctx, input) => {\n if (input.discountPercent <= 0 || input.discountPercent > 100) {"}]},{"id":"promotion-rule-stores-the-wrong-discount","scenario":"tracks/ecommerce/scenarios/progression-promotion-rules.json","targets":["ecommerce.progression.promotion-rules.promotion-rule-values.620a"],"desc":"Promotion creation stores a one-percent discount instead of the submitted value.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"ctx.db.promotion.insert({ id: 0n, ...input, code: input.code.trim(), redemptions: 0 });","replace":"ctx.db.promotion.insert({ id: 0n, ...input, discountPercent: 1, code: input.code.trim(), redemptions: 0 });"}]},{"id":"staff-cannot-open-staff-tools","scenario":"tracks/ecommerce/scenarios/progression-staff-access.json","targets":["ecommerce.progression.staff-access.staff-access.601a"],"desc":"Deny administrators entry to staff tools while keeping ordinary staff access working.","file":"client/src/App.tsx","edits":[{"find":"{(isStaff || isAdmin) && (\n ({","replace":"return [...ctx.db.notification.iter()].map(row => ({"}]},{"id":"support-history-is-lost-on-fresh-account-login","scenario":"tracks/ecommerce/scenarios/progression-support-history.json","targets":["ecommerce.spec.state-durability.support-history-reload.612a"],"desc":"Resolve customer support ownership by transport identity only, omitting the account ownership path. Initial submission, same-identity reload, and stored tickets remain intact; fresh account login cannot recover the history.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"!!actor && (actor.isAdmin || actor.isStaff || row.accountId === accountId))","replace":"!!actor && (actor.isAdmin || actor.isStaff || row.creatorIdentity.toHexString() === sender))"}]},{"id":"support-history-leaks-across-customers","scenario":"tracks/ecommerce/scenarios/progression-support-history.json","targets":["ecommerce.spec.access-control.support-history-privacy.612b","ecommerce.spec.access-control.support-history-logout.612d"],"desc":"Return all support tickets, exposing them to other customers and signed-out visitors.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":".filter(row => isGuestTicketCreator(sender, row.creatorIdentity.toHexString(), row.accountId) ||\n !!actor && (actor.isAdmin || actor.isStaff || row.accountId === accountId))","replace":".filter(() => true)"}]},{"id":"visitor-support-reference-is-hidden","scenario":"tracks/ecommerce/scenarios/progression-support-intake.json","targets":["ecommerce.progression.support-intake.support-intake.610a"],"desc":"A visitor can create a support ticket but the returned reference is not rendered.","file":"client/src/components/ProgressionWorkbench.tsx","edits":[{"find":"
{supportReference}
","replace":"
"}]},{"id":"support-assignment-is-discarded","scenario":"tracks/ecommerce/scenarios/progression-support-triage.json","targets":["ecommerce.progression.support-triage.support-assignment.611a"],"desc":"Support triage saves status and priority but discards the assignee.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"ctx.db.supportTicket.id.update({ ...ticket, assigneeId: nextAssigneeId, priority, status });","replace":"ctx.db.supportTicket.id.update({ ...ticket, assigneeId: undefined, priority, status });"}]},{"id":"support-priority-is-discarded","scenario":"tracks/ecommerce/scenarios/progression-support-triage.json","targets":["ecommerce.progression.support-triage.support-priority.611b"],"desc":"Support triage always saves normal priority instead of the submitted value.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"ctx.db.supportTicket.id.update({ ...ticket, assigneeId: nextAssigneeId, priority, status });","replace":"ctx.db.supportTicket.id.update({ ...ticket, assigneeId: nextAssigneeId, priority: 'normal', status });"}]},{"id":"support-status-is-discarded","scenario":"tracks/ecommerce/scenarios/progression-support-triage.json","targets":["ecommerce.progression.support-triage.support-status.611c"],"desc":"Support triage preserves the old status instead of the submitted value.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"ctx.db.supportTicket.id.update({ ...ticket, assigneeId: nextAssigneeId, priority, status });","replace":"ctx.db.supportTicket.id.update({ ...ticket, assigneeId: nextAssigneeId, priority, status: ticket.status });"}]},{"id":"nonpositive-cart-quantity-is-treated-as-removal","scenario":"tracks/ecommerce/scenarios/01-cart-boundary.json","targets":["ecommerce.spec.access-control.cart-boundary.109b"],"desc":"Accept a negative quantity and remove the cart line instead of refusing the request.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" if (quantity < 1) throw new SenderError('Quantity must be at least 1.');\n const existing = findCartLine(ctx, acc.id, itemId);\n if (!existing) throw new SenderError('That item is not in your cart.');\n if (existing.bundlePrice > 0) throw new SenderError('Remove and re-add a whole bundle.');\n replaceReservation(ctx, acc.id, itemId, quantity);\n ctx.db.cartItem.id.update({ ...existing, quantity });","replace":" const existing = findCartLine(ctx, acc.id, itemId);\n if (!existing) throw new SenderError('That item is not in your cart.');\n if (quantity < 1) {\n ctx.db.cartItem.id.delete(existing.id);\n return;\n }\n if (existing.bundlePrice > 0) throw new SenderError('Remove and re-add a whole bundle.');\n replaceReservation(ctx, acc.id, itemId, quantity);\n ctx.db.cartItem.id.update({ ...existing, quantity });"}]},{"id":"admin-restock-preserves-existing-stock","scenario":"tracks/ecommerce/scenarios/01-warehouse-stock-live-staff.json","targets":["ecommerce.spec.live-state.warehouse-stock.7c"],"desc":"Accept an administrator restock but write the existing quantity back unchanged.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" ctx.db.stock.insert({ ...existing, quantity: existing.quantity + quantity });","replace":" ctx.db.stock.insert({ ...existing, quantity: existing.quantity });"}]},{"id":"operator-authorization-allows-customer-price-change","scenario":"tracks/ecommerce/scenarios/02-strengthened.json","targets":["ecommerce.operations-access.operator-authorization.201b"],"desc":"The price reducer drops its administrator role gate.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" (ctx, { itemId, price }) => {\n requireAdmin(ctx);","replace":" (ctx, { itemId, price }) => {\n // mutant: no administrator role check"}]},{"id":"fulfilment-queue-allows-customer-shipping","scenario":"tracks/ecommerce/scenarios/02-self-contained.json","targets":["ecommerce.operations-access.fulfilment-queue.1e"],"desc":"The shipping reducer drops the staff role check while retaining the pending-order guard.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"export const shipOrder = spacetimedb.reducer({ orderId: t.u64() }, (ctx, { orderId }) => {\n requireStaffOrAdmin(ctx);","replace":"export const shipOrder = spacetimedb.reducer({ orderId: t.u64() }, (ctx, { orderId }) => {\n // mutant: no staff role check"}]},{"id":"catalog-search-keeps-pre-change-price","scenario":"tracks/ecommerce/scenarios/02-live-price.json","targets":["ecommerce.returns-pricing.price-history.4b"],"desc":"The search result renderer caches each item's first visible price and ignores later live price updates.","file":"client/src/components/ItemCard.tsx","edits":[{"find":"import { ItemRow } from '../types';","replace":"import { useRef } from 'react';\nimport { ItemRow } from '../types';"},{"find":" const outOfStock = stock <= 0;\n const lowStock = !outOfStock && stock <= 5;","replace":" const outOfStock = stock <= 0;\n const lowStock = !outOfStock && stock <= 5;\n // mutant: the card retains the first price it renders\n const firstPrice = useRef(item.price);"},{"find":" {formatMoney(item.price)}","replace":" {formatMoney(firstPrice.current)}"}]},{"id":"open-cart-keeps-pre-change-price","scenario":"tracks/ecommerce/scenarios/progression-price-cart-checkout.json","targets":["ecommerce.returns-pricing.price-history.4c"],"desc":"The open-cart memo ignores reactive item-table price updates while checkout still reads the current server price.","file":"client/src/App.tsx","edits":[{"find":" [cartRows, items, stockByItem]","replace":" [cartRows, stockByItem]"}]},{"id":"catalog-price-rewrites-receipts","scenario":"tracks/ecommerce/scenarios/02-paid-price-history.json","targets":["ecommerce.returns-pricing.price-history.4a"],"desc":"Changing a catalog price cascades into saved order lines and recomputes historical order totals inside the reducer transaction.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" ctx.db.item.id.update({ ...it, price });","replace":" ctx.db.item.id.update({ ...it, price });\n const repricedOrderIds = new Set();\n for (const line of ctx.db.orderItem.iter()) {\n if (line.itemId !== itemId) continue;\n ctx.db.orderItem.id.update({ ...line, unitPrice: price });\n repricedOrderIds.add(line.orderId);\n }\n for (const orderId of repricedOrderIds) {\n const historical = ctx.db.customerOrder.id.find(orderId);\n if (!historical) continue;\n let total = 0;\n for (const line of ctx.db.orderItem.orderId.filter(orderId)) total += line.unitPrice * line.quantity;\n ctx.db.customerOrder.id.update({ ...historical, total });\n }"}]},{"id":"catalog-price-rewrites-earned-revenue","scenario":"tracks/ecommerce/scenarios/02-invariants.json","targets":["ecommerce.returns-pricing.refund-accounting.203b"],"desc":"Changing a catalog price cascades into saved order lines and recomputes historical order totals and revenue inside the reducer transaction.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" ctx.db.item.id.update({ ...it, price });","replace":" ctx.db.item.id.update({ ...it, price });\n const repricedOrderIds = new Set();\n for (const line of ctx.db.orderItem.iter()) {\n if (line.itemId !== itemId) continue;\n ctx.db.orderItem.id.update({ ...line, unitPrice: price });\n repricedOrderIds.add(line.orderId);\n }\n for (const orderId of repricedOrderIds) {\n const historical = ctx.db.customerOrder.id.find(orderId);\n if (!historical) continue;\n let total = 0;\n for (const line of ctx.db.orderItem.orderId.filter(orderId)) total += line.unitPrice * line.quantity;\n ctx.db.customerOrder.id.update({ ...historical, total });\n }"}]},{"id":"returned-line-marker-omitted","scenario":"tracks/ecommerce/scenarios/02-strengthened.json","targets":["ecommerce.returns-pricing.cancellation-and-return.3c"],"desc":"A returned order line keeps its persisted returned state, restored stock, and adjusted revenue but omits the visible returned marker.","file":"client/src/components/OrdersPanel.tsx","edits":[{"find":"{item.returned && Returned}","replace":"{false && Returned}"}]},{"id":"direct-review-access-is-not-checked","scenario":"tracks/ecommerce/scenarios/progression-review-access.json","targets":["ecommerce.progression.review-access-specifications.review-eligibility-direct.618a"],"desc":"The direct review action accepts a review from a customer who did not buy the item.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" if (!bought) throw new SenderError('You can only review items you have purchased.');","replace":" // mutant: purchase eligibility is not checked"}]},{"id":"support-history-rows-are-hidden","scenario":"tracks/ecommerce/scenarios/progression-support-history.json","targets":["ecommerce.progression.support-history.support-history.612c","ecommerce.spec.state-durability.support-history-reload.612a","ecommerce.spec.access-control.support-history-privacy.612b","ecommerce.spec.access-control.support-history-logout.612d"],"desc":"Hide submitted support ticket rows while leaving the submission reference available. History, reload, privacy, and logout require the owner to see the ticket first. This breaks those positive observations; it does not create a privacy leak or remove stored data.","file":"client/src/components/ProgressionWorkbench.tsx","edits":[{"find":"data-role=\"support-ticket\"","replace":"data-role=\"support-ticket\" style={{ display: \"none\" }}"}]},{"id":"authorized-restock-does-not-change-stock","scenario":"tracks/ecommerce/scenarios/01-admin-write-staff.json","targets":["ecommerce.feature.warehouse-admin.admin-write.103a"],"desc":"Accept an administrator restock without changing warehouse stock.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" if (existing) {\n ctx.db.stock.by_item_warehouse.delete([itemId, warehouseId]);\n ctx.db.stock.insert({ ...existing, quantity: existing.quantity + quantity });\n } else {\n ctx.db.stock.insert({ item_id: itemId, warehouse_id: warehouseId, quantity });\n }\n","replace":" // mutant: accept restock without changing stock\n"}]},{"id":"low-stock-threshold-is-two-units","scenario":"tracks/ecommerce/scenarios/02-low-stock.json","targets":["ecommerce.inventory-operations.operational-views.5e","ecommerce.spec.live-state.inventory-dashboard.5a"],"desc":"The dashboard lists only items with two units or fewer, so the seeded three-unit item is missing from the low-stock view. The live check in the same scenario opens with the identical observation and necessarily fails with it.","file":"client/src/App.tsx","edits":[{"find":"const LOW_STOCK_THRESHOLD = 10;","replace":"const LOW_STOCK_THRESHOLD = 2;"}]},{"id":"category-totals-count-only-since-the-dashboard-opened","scenario":"tracks/ecommerce/scenarios/02-operational-category-totals.json","targets":["ecommerce.inventory-operations.operational-views.5f"],"desc":"The category table shows units and revenue accumulated since the dashboard was opened instead of the stored totals, so a reload resets both to zero and the totals recorded before the reload are not reproduced. Live movement within one open dashboard is still correct, so the live check is unaffected.","file":"client/src/components/AdminPanel.tsx","edits":[{"find":"import { useState } from 'react';","replace":"import { useRef, useState } from 'react';"},{"find":" return (\n
","replace":" const openingTotals = useRef | null>(null);\n if (openingTotals.current === null && categoryTotals.length > 0) {\n openingTotals.current = new Map(\n categoryTotals.map((cat): [bigint, { units: number; revenue: number }] => [\n cat.categoryId,\n { units: cat.unitsSold, revenue: cat.revenue },\n ])\n );\n }\n const sessionTotals = categoryTotals.map((cat) => {\n const opening = openingTotals.current?.get(cat.categoryId);\n return {\n ...cat,\n unitsSold: cat.unitsSold - (opening?.units ?? 0),\n revenue: cat.revenue - (opening?.revenue ?? 0),\n };\n });\n\n return (\n
"},{"find":" {categoryTotals.map((cat) => (","replace":" {sessionTotals.map((cat) => ("}]},{"id":"profile-summary-ignores-a-profile-saved-this-session","scenario":"tracks/ecommerce/scenarios/progression-customer-profile.json","targets":["ecommerce.progression.customer-profile.customer-profile.620c"],"desc":"Hide the profile summary immediately after saving in the current view. Stored profile data and a reopened or reloaded view remain correct, so fresh-login durability and privacy positive controls remain observable.","file":"client/src/components/ProgressionWorkbench.tsx","edits":[{"find":" const [profileName, setProfileName] = useState(profile?.name ?? '');","replace":" const [profileName, setProfileName] = useState(profile?.name ?? '');\n const [profileSavedHere, setProfileSavedHere] = useState(false);"},{"find":"onClick={() => reducers?.saveProfile({ name: profileName, address: profileAddress })}","replace":"onClick={() => { setProfileSavedHere(true); return reducers?.saveProfile({ name: profileName, address: profileAddress }); }}"},{"find":"
{profile?.name} {profile?.address}
","replace":"
{!profileSavedHere && <>{profile?.name} {profile?.address}}
"}]},{"id":"stored-support-replies-are-hidden-after-reload","scenario":"tracks/ecommerce/scenarios/progression-managed-support-shared.json","targets":["ecommerce.progression.managed-support.managed-support.613c"],"desc":"Replies already stored when the page loads are hidden and only replies that arrive while the page is open are shown, so a reloaded customer or staff member cannot see the earlier exchange. The live shared-case check exchanges only new replies and is unaffected.","file":"client/src/App.tsx","edits":[{"find":"import { useEffect, useMemo, useState } from 'react';","replace":"import { useEffect, useMemo, useRef, useState } from 'react';"},{"find":" const [supportReplyRows] = useTable(tables.visibleSupportReplies);","replace":" const [liveSupportReplyRows, supportRepliesReady] = useTable(tables.visibleSupportReplies);\n const openedSupportReplies = useRef | null>(null);\n if (openedSupportReplies.current === null && supportRepliesReady) {\n openedSupportReplies.current = new Set(\n liveSupportReplyRows.map((row) => `${row.ticketId}:${row.author}:${row.body}`)\n );\n }\n const supportReplyRows = liveSupportReplyRows.filter(\n (row) => !openedSupportReplies.current?.has(`${row.ticketId}:${row.author}:${row.body}`)\n );"}]},{"id":"saving-notification-preferences-resets-the-toggles","scenario":"tracks/ecommerce/scenarios/progression-notification-preferences.json","targets":["ecommerce.progression.notification-preferences.notification-preferences.630c"],"desc":"Saving sends the chosen preferences but resets both toggles to off and stops the form from following the stored row for the rest of the session, so the saved choice cannot be seen until a reload. The reload and cross-account checks read the stored row on a fresh page and are unaffected.","file":"client/src/components/ProgressionWorkbench.tsx","edits":[{"find":" useEffect(() => {\n setOrderEnabled(preferences?.orderEnabled ?? false);\n setStockEnabled(preferences?.stockEnabled ?? false);\n }, [preferences?.orderEnabled, preferences?.stockEnabled]);","replace":" const [preferencesSubmitted, setPreferencesSubmitted] = useState(false);\n useEffect(() => {\n if (preferencesSubmitted) return;\n setOrderEnabled(preferences?.orderEnabled ?? false);\n setStockEnabled(preferences?.stockEnabled ?? false);\n }, [preferences?.orderEnabled, preferences?.stockEnabled, preferencesSubmitted]);"},{"find":"onClick={() => reducers?.saveNotificationPreferences({ orderEnabled, stockEnabled })}","replace":"onClick={() => { reducers?.saveNotificationPreferences({ orderEnabled, stockEnabled }); setPreferencesSubmitted(true); setOrderEnabled(false); setStockEnabled(false); }}"}]},{"id":"saving-a-staff-role-snaps-the-input-back-to-the-stored-role","scenario":"tracks/ecommerce/scenarios/progression-staff-roles.json","targets":["ecommerce.progression.staff-roles.staff-roles.621c"],"desc":"Saving a role sends the new role to the server but snaps the visible input back to the role stored before the save for the rest of the session, so the administrator cannot see the assignment take. A reload renders the stored role, so the durability and boundary checks are unaffected.","file":"client/src/components/ProgressionWorkbench.tsx","edits":[{"find":" ","replace":" "}]},{"id":"fulfilment-queue-is-frozen-at-page-load","scenario":"tracks/ecommerce/scenarios/02-fulfilment-live.json","targets":["ecommerce.spec.live-state.fulfilment-queue.1a"],"desc":"The fulfilment queue renders the rows delivered with the page's initial subscription and ignores later updates, so an order placed while the queue is open never appears without a reload.","file":"client/src/App.tsx","edits":[{"find":"import { useEffect, useMemo, useState } from 'react';","replace":"import { useEffect, useMemo, useRef, useState } from 'react';"},{"find":" const [queueRows] = useTable(tables.fulfilmentQueue);","replace":" const [liveQueueRows, queueReady] = useTable(tables.fulfilmentQueue);\n const openedQueueRows = useRef(null);\n if (openedQueueRows.current === null && queueReady) openedQueueRows.current = liveQueueRows;\n const queueRows = openedQueueRows.current ?? liveQueueRows;"}]},{"id":"low-stock-list-is-frozen-at-page-load","scenario":"tracks/ecommerce/scenarios/02-low-stock.json","targets":["ecommerce.spec.live-state.inventory-dashboard.5a"],"desc":"The low-stock list is computed once from the first complete stock snapshot and never recomputed, so items no longer enter or leave it as stock is restocked or sold. The seeded low item is in that first snapshot, so the static listing check is unaffected.","file":"client/src/App.tsx","edits":[{"find":"import { useEffect, useMemo, useState } from 'react';","replace":"import { useEffect, useMemo, useRef, useState } from 'react';"},{"find":" const lowStockItems = useMemo(\n () =>\n [...items]\n .filter((i) => (stockByItem.get(i.id) ?? 0) <= LOW_STOCK_THRESHOLD)\n .sort((a, b) => (stockByItem.get(a.id) ?? 0) - (stockByItem.get(b.id) ?? 0)),\n [items, stockByItem]\n );","replace":" const liveLowStockItems = useMemo(\n () =>\n [...items]\n .filter((i) => (stockByItem.get(i.id) ?? 0) <= LOW_STOCK_THRESHOLD)\n .sort((a, b) => (stockByItem.get(a.id) ?? 0) - (stockByItem.get(b.id) ?? 0)),\n [items, stockByItem]\n );\n const openedLowStockItems = useRef(null);\n if (openedLowStockItems.current === null && items.length > 0 && stocks.length > 0) {\n openedLowStockItems.current = liveLowStockItems;\n }\n const lowStockItems = openedLowStockItems.current ?? liveLowStockItems;"}]},{"id":"category-totals-are-frozen-at-page-load","scenario":"tracks/ecommerce/scenarios/02-operational-category-totals.json","targets":["ecommerce.spec.live-state.sales-dashboard.5b"],"desc":"The category totals render the first non-empty row set received and ignore later updates, so a purchase does not move units or revenue while the dashboard is open. A reload receives the stored totals, so the reload check is unaffected.","file":"client/src/App.tsx","edits":[{"find":"import { useEffect, useMemo, useState } from 'react';","replace":"import { useEffect, useMemo, useRef, useState } from 'react';"},{"find":" const [categoryTotalRows] = useTable(tables.categoryTotals);","replace":" const [liveCategoryTotalRows] = useTable(tables.categoryTotals);\n const openedCategoryTotalRows = useRef(null);\n if (openedCategoryTotalRows.current === null && liveCategoryTotalRows.length > 0) {\n openedCategoryTotalRows.current = liveCategoryTotalRows;\n }\n const categoryTotalRows = openedCategoryTotalRows.current ?? liveCategoryTotalRows;"}]},{"id":"warehouse-totals-are-frozen-at-page-load","scenario":"tracks/ecommerce/scenarios/02-transfer-totals.json","targets":["ecommerce.spec.live-state.stock-transfers.2b"],"desc":"The per-warehouse totals are computed once from the first stock snapshot and never recomputed, so a transfer moves neither warehouse figure while the dashboard is open.","file":"client/src/App.tsx","edits":[{"find":"import { useEffect, useMemo, useState } from 'react';","replace":"import { useEffect, useMemo, useRef, useState } from 'react';"},{"find":" const stockByWarehouse = useMemo(() => {\n const map = new Map();\n for (const row of stocks) {\n map.set(row.warehouseId, (map.get(row.warehouseId) ?? 0) + row.quantity);\n }\n return map;\n }, [stocks]);","replace":" const liveStockByWarehouse = useMemo(() => {\n const map = new Map();\n for (const row of stocks) {\n map.set(row.warehouseId, (map.get(row.warehouseId) ?? 0) + row.quantity);\n }\n return map;\n }, [stocks]);\n const openedStockByWarehouse = useRef(null);\n if (openedStockByWarehouse.current === null && liveStockByWarehouse.size > 0) {\n openedStockByWarehouse.current = liveStockByWarehouse;\n }\n const stockByWarehouse = openedStockByWarehouse.current ?? liveStockByWarehouse;"}]},{"id":"transfer-skips-the-source-holding-check","scenario":"tracks/ecommerce/scenarios/02-transfer-overdraw.json","targets":["ecommerce.spec.transactional-integrity.stock-transfer-overdraw.2c"],"desc":"The serialized transfer reducer no longer checks that the source warehouse holds the requested quantity, so an overdraw is accepted instead of refused and the source quantity wraps below zero.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" if (available < quantity) {\n throw new SenderError(`Not enough stock in source warehouse: only ${available} available.`);\n }","replace":" // mutant: the source warehouse holding is not checked"}]},{"id":"credit-checkout-ignores-wallet","desc":"A credit checkout pays entirely externally despite available credit.","scenario":"tracks/ecommerce/scenarios/progression-store-credit.json","targets":["ecommerce.feature.store-credit.store-credit-750.750a"],"file":"backend/spacetimedb/src/index.ts","edits":[{"find":" const creditMinor = useCredit ? Math.min(wallet?.amountMinor ?? 0,totalMinor) : 0;","replace":" const creditMinor = 0;"}]},{"id":"credit-grant-replay-increments-balance","desc":"Replaying a grant applies its credit to the wallet again.","scenario":"tracks/ecommerce/scenarios/progression-store-credit.json","targets":["ecommerce.spec.store-credit.production-752.752a"],"file":"backend/spacetimedb/src/index.ts","edits":[{"find":" if (existing.amountMinor !== amountMinor) throw new SenderError('Reference identifies another grant.');\n return;","replace":" if (existing.amountMinor !== amountMinor) throw new SenderError('Reference identifies another grant.');\n const wallet = ctx.db.creditWallet.accountId.find(accountId)!;\n ctx.db.creditWallet.accountId.update({ ...wallet, amountMinor: wallet.amountMinor + amountMinor });\n return;"}]},{"id":"customer-can-grant-credit","desc":"Customer authentication is accepted without staff authorization.","scenario":"tracks/ecommerce/scenarios/progression-store-credit.json","targets":["ecommerce.spec.store-credit.production-753.753a"],"file":"backend/spacetimedb/src/index.ts","edits":[{"find":" (ctx, { accountId, amountMinor, reference }) => {\n requireStaffOrAdmin(ctx);","replace":" (ctx, { accountId, amountMinor, reference }) => {\n requireAccount(ctx);"}]},{"id":"split-refund-does-not-restore-credit","desc":"The refund is recorded but its original wallet credit is not restored.","scenario":"tracks/ecommerce/scenarios/progression-split-tender-refunds.json","targets":["ecommerce.feature.split-tender-refunds.split-tender-refunds-751.751a"],"file":"backend/spacetimedb/src/index.ts","edits":[{"find":" refundOrderCredit(ctx, order, order.total);","replace":" // mutant: omit wallet restoration"}]},{"id":"split-refund-duplicates-credit","desc":"A refund credits the wallet twice while recording one refund.","scenario":"tracks/ecommerce/scenarios/progression-split-tender-refunds.json","targets":["ecommerce.spec.split-tender-refunds.production-756.756a"],"file":"backend/spacetimedb/src/index.ts","edits":[{"find":"amountMinor: wallet.amountMinor + delta","replace":"amountMinor: wallet.amountMinor + delta * 2"}]},{"id":"subscription-skips-due-purchase","desc":"Due deliveries are recorded as skipped although stock is available.","scenario":"tracks/ecommerce/scenarios/progression-subscriptions.json","targets":["ecommerce.feature.subscriptions.subscriptions-760.760a"],"file":"backend/spacetimedb/src/subscriptions.ts","edits":[{"find":" const orderId = purchase(row.accountId, row.itemId, row.quantity, row.price);","replace":" const orderId: bigint | null = null;"}]},{"id":"subscription-allows-foreign-cancellation","desc":"A customer can cancel another customer subscription.","scenario":"tracks/ecommerce/scenarios/progression-subscriptions.json","targets":["ecommerce.spec.subscriptions.production-762.762a"],"file":"backend/spacetimedb/src/subscriptions.ts","edits":[{"find":" if (!row || row.accountId !== accountId) throw new SenderError('Subscription access denied.');","replace":" if (!row) throw new SenderError('Subscription access denied.');"}]},{"id":"subscription-pause-is-not-recorded","desc":"Pause acknowledges the request but the subscription remains active.","scenario":"tracks/ecommerce/scenarios/progression-subscriptions.json","targets":["ecommerce.spec.subscriptions.production-763.763a"],"file":"backend/spacetimedb/src/subscriptions.ts","edits":[{"find":" ctx.db.purchaseSubscription.id.update({ ...row, status: 'paused', pausedMicros: now });","replace":" ctx.db.purchaseSubscription.id.update({ ...row, status: 'active', pausedMicros: now });"}]},{"id":"credit-checkout-retains-purchased-cart","scenario":"tracks/ecommerce/scenarios/progression-store-credit.json","targets":["ecommerce.spec.store-credit.production-754.754a"],"desc":"The purchased cart remains available instead of being consumed by checkout.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" for (const line of lines) ctx.db.cartItem.id.delete(line.id);","replace":" // mutant: checked-out lines remain in the cart"}]},{"id":"reconnection-erases-stored-credit","desc":"A new connection erases stored wallet credit; the fresh view after restart must catch the data loss.","file":"backend/spacetimedb/src/index.ts","scenario":"tracks/ecommerce/scenarios/progression-store-credit.json","targets":["ecommerce.spec.store-credit.production-755.755a"],"edits":[{"find":"export const onConnect = spacetimedb.clientConnected((_ctx) => {});","replace":"export const onConnect = spacetimedb.clientConnected(ctx => { for (const row of ctx.db.creditWallet.iter()) ctx.db.creditWallet.accountId.update({ ...row, amountMinor: 0 }); });"}]},{"id":"reconnection-cancels-pending-subscriptions","desc":"A new connection cancels pending subscriptions; restarting and reconnecting must preserve this work.","file":"backend/spacetimedb/src/index.ts","scenario":"tracks/ecommerce/scenarios/progression-subscriptions.json","targets":["ecommerce.spec.subscriptions.production-761.761a"],"edits":[{"find":"export const onConnect = spacetimedb.clientConnected((_ctx) => {});","replace":"export const onConnect = spacetimedb.clientConnected(ctx => { for (const row of ctx.db.purchaseSubscription.iter()) if (row.status === 'active') ctx.db.purchaseSubscription.id.update({ ...row, status: 'cancelled' }); });"}]},{"id":"bundle-definition-loses-component-quantity","scenario":"tracks/ecommerce/scenarios/progression-product-bundles.json","targets":["ecommerce.feature.product-bundles.product-bundles.740a"],"desc":"definition loses component quantity","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"return { ...component, itemId: String(product.id) };","replace":"return { ...component, quantity: 1, itemId: String(product.id) };"}]},{"id":"bundle-catalog-write-allows-customers","scenario":"tracks/ecommerce/scenarios/progression-product-bundles.json","targets":["ecommerce.spec.bundle-integrity.bundle-743.743a"],"desc":"catalog write allows customers","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"const actor = requireStaffOrAdmin(ctx);\n if (!actor.isAdmin && ctx.db.staffRole.accountId.find(actor.id)?.role !== 'catalog') {","replace":"const actor = requireAccount(ctx);\n if (false) {"}]},{"id":"bundle-checkout-price-not-snapshot","scenario":"tracks/ecommerce/scenarios/progression-bundle-checkout.json","targets":["ecommerce.feature.bundle-checkout.bundle-checkout.741a"],"desc":"checkout price not snapshot","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"bundlePrice: product.price, bundleComponentsJson: definition.componentsJson","replace":"bundlePrice: product.price + 1, bundleComponentsJson: definition.componentsJson"}]},{"id":"bundle-return-loses-original-components","scenario":"tracks/ecommerce/scenarios/progression-bundle-returns.json","targets":["ecommerce.feature.bundle-returns.bundle-returns.742a"],"desc":"return loses original components","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"for (const line of bundles) {\n restoreOrderItemStock(ctx, line);","replace":"for (const line of bundles) {\n // mutant: original stock is not restored"}]},{"id":"bundle-return-replay-restocks-again","scenario":"tracks/ecommerce/scenarios/progression-bundle-returns.json","targets":["ecommerce.spec.bundle-integrity.bundle-742.742b"],"desc":"return replay restocks again","file":"backend/spacetimedb/src/index.ts","edits":[{"find":".filter(row => row.isBundle && !row.returned);","replace":".filter(row => row.isBundle);"}]},{"id":"bundle-return-crosses-account-boundary","scenario":"tracks/ecommerce/scenarios/progression-bundle-returns.json","targets":["ecommerce.spec.bundle-integrity.bundle-748.748a"],"desc":"return crosses account boundary","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"if (!order || order.accountId !== account.id || !['shipped', 'delivered'].includes(order.status))","replace":"if (!order || !['shipped', 'delivered'].includes(order.status))"}]},{"id":"bundle-components-can-overdraw","scenario":"tracks/ecommerce/scenarios/progression-bundle-checkout.json","targets":["ecommerce.spec.bundle-integrity.bundle-744.744a","ecommerce.spec.bundle-integrity.bundle-745.745a"],"desc":"components can overdraw","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"if (!allocations) throw new SenderError('Not enough stock to reserve.');","replace":"if (!allocations) { if (bundleId) return; throw new SenderError('Not enough stock to reserve.'); }"}]},{"id":"bundle-checkout-reuses-reservation","scenario":"tracks/ecommerce/scenarios/progression-bundle-checkout.json","targets":["ecommerce.spec.bundle-integrity.bundle-747.747a"],"desc":"checkout reuses reservation","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"for (const row of held) ctx.db.reservation.id.delete(row.id);\n processReorderRules(ctx, p.itemId);","replace":"// mutant: reservations survive checkout\n processReorderRules(ctx, p.itemId);"},{"find":"for (const line of lines) ctx.db.cartItem.id.delete(line.id);","replace":"// mutant: cart survives checkout"}]},{"id":"bundle-expiry-does-not-release-components","scenario":"tracks/ecommerce/scenarios/progression-bundle-checkout.json","targets":["ecommerce.spec.bundle-integrity.bundle-746.746a"],"desc":"Expired bundle reservations retain their component stock after restart.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"if (row.expired || row.expiresMicros > now) continue;\n restoreStock(ctx, row.stockItemId || row.itemId, row.warehouseId, row.quantity);","replace":"if (row.expired || row.expiresMicros > now) continue;\n if (!row.stockItemId) restoreStock(ctx, row.itemId, row.warehouseId, row.quantity);"}]},{"id":"return-after-support-refund-is-blocked","scenario":"tracks/ecommerce/scenarios/progression-support-return-interaction.json","targets":["ecommerce.feature.split-tender-refunds.return-refund-interaction.757a"],"desc":"Reject a valid physical return after a financial refund.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" if (target.returned) throw new SenderError('Item already returned.');","replace":" if (target.returned || order.refundedTotal > 0) throw new SenderError('Item already returned.');"}]},{"id":"support-refund-after-return-pays-twice","scenario":"tracks/ecommerce/scenarios/progression-support-return-interaction.json","targets":["ecommerce.feature.split-tender-refunds.return-refund-interaction.757b"],"desc":"Pay the full order again after the physical return already refunded it.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":" const amount = order.total - order.refundedTotal;","replace":" const amount = order.total;"},{"find":"refundedTotal: order.total, status: order.status","replace":"refundedTotal: order.refundedTotal + amount, status: order.status"}]},{"id":"support-history-leaks-to-signed-out-visitors","scenario":"tracks/ecommerce/scenarios/progression-support-history.json","targets":["ecommerce.spec.access-control.support-history-logout.612d"],"desc":"Disclose support tickets to signed-out visitors while leaving signed-in ownership filtering unchanged.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":".filter(row => isGuestTicketCreator(sender, row.creatorIdentity.toHexString(), row.accountId) ||","replace":".filter(row => !actor || isGuestTicketCreator(sender, row.creatorIdentity.toHexString(), row.accountId) ||"}]},{"id":"checkout-crash-integrity","scenario":"tracks/ecommerce/scenarios/progression-checkout-crash.json","targets":["ecommerce.spec.state-durability.checkout-crash-integrity.910a"],"desc":"A lifecycle callback changes a prepared or cleared cart to quantity two, leaving neither a legal rollback nor a complete checkout.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"export const onDisconnect = spacetimedb.clientDisconnected((_ctx) => {});","replace":"export const onDisconnect = spacetimedb.clientDisconnected((ctx) => { for (const row of ctx.db.cartItem.iter()) if ([...ctx.db.customerOrder.iter()].some(order => order.accountId === row.accountId)) ctx.db.cartItem.id.update({ ...row, quantity: 2 }); });"}]},{"id":"checkout-crash-durability","scenario":"tracks/ecommerce/scenarios/progression-checkout-crash.json","targets":["ecommerce.spec.state-durability.checkout-crash-durability.910b"],"desc":"A lifecycle callback corrupts earlier order totals. The unchanged prepared snapshots and acknowledged baseline must expose the damage.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"export const onDisconnect = spacetimedb.clientDisconnected((_ctx) => {});","replace":"export const onDisconnect = spacetimedb.clientDisconnected((ctx) => { for (const order of ctx.db.customerOrder.iter()) if ([...ctx.db.cartItem.iter()].some(row => row.accountId === order.accountId)) ctx.db.customerOrder.id.update({ ...order, total: 0 }); });"}]},{"id":"review-script-unsafe-render","scenario":"tracks/ecommerce/scenarios/progression-review-script.json","targets":["ecommerce.progression.review-access-specifications.stored-review-script.9180a"],"desc":"Render stored review text as HTML so it executes in another customer session.","file":"client/src/components/ItemDetail.tsx","edits":[{"find":"
{r.comment}
","replace":"
"}]},{"id":"review-script-reject-all","scenario":"tracks/ecommerce/scenarios/progression-review-script.json","targets":["ecommerce.progression.review-access-specifications.stored-review-script.9180a"],"desc":"Reject all nonempty reviews, including the required benign review; absence of script is insufficient.","file":"backend/spacetimedb/src/index.ts","edits":[{"find":"(ctx, { itemId, rating, comment }) => {","replace":"(ctx, { itemId, rating, comment }) => {\n if (comment.length > 0) throw new SenderError(\"Review rejected\");"}]}]}}} diff --git a/tools/stack-bench/qualification-evidence/ecommerce-l3-e804c1302/spacetime-targeted.json b/tools/stack-bench/qualification-evidence/ecommerce-l3-e804c1302/spacetime-targeted.json new file mode 100644 index 00000000000..fb3a6b2b015 --- /dev/null +++ b/tools/stack-bench/qualification-evidence/ecommerce-l3-e804c1302/spacetime-targeted.json @@ -0,0 +1,136 @@ +{ + "artifactSchemaVersion": 2, + "kind": "reference_qualification", + "id": "reference-live-spacetime-20260918002257-31", + "attempt": { + "id": "reference-live-spacetime-20260918002257-31", + "parentId": null + }, + "timestamps": { + "startedAt": "2026-09-18T00:22:58.000Z", + "completedAt": "2026-09-18T00:24:46.820Z" + }, + "identities": { + "engine": { + "id": "stack-bench", + "sha256": "581451119c180f50fd478aa2c17e1fa766fd38e7648e01d8a354334df1b606d3" + }, + "recipe": { + "id": "ecommerce.progression-catalog", + "sha256": "53fbb8093b2335837d88c246f04da99858c40b57ce24d17fbd2b6c815abdb62d" + }, + "fixture": { + "id": "ecommerce-reference-spacetime", + "sha256": "7ba1f548e89f461b95b5caf843b0fbcf2b81278428d02869d7f47e1a199eaf6e" + }, + "calibration": { + "id": "ecommerce.dependency-l3-calibration", + "sha256": "253174720de8d80e884e764e4d8018c0a98e1c54b364b33f7679aa189af8d1bd" + }, + "experiment": null, + "agentAdapter": null, + "stackAdapter": { + "id": "spacetime", + "sha256": null + }, + "packs": [] + }, + "payload": { + "fixture": "ecommerce-reference-spacetime", + "fixtureSha256": "7ba1f548e89f461b95b5caf843b0fbcf2b81278428d02869d7f47e1a199eaf6e", + "requiredRepetitions": 1, + "isolation": "docker", + "runner": { + "schemaVersion": 1, + "mode": "appliance", + "platform": "linux", + "architecture": "x64", + "hostname": "docker-desktop", + "dockerEngineVersion": "29.6.2", + "dockerOs": "linux", + "dockerArchitecture": "x86_64", + "kernelVersion": "6.6.87.2-microsoft-standard-WSL2", + "cpuCount": 32, + "memoryBytes": 49232842752, + "containersRunning": 11, + "packageRegistry": "http://127.0.0.1:4873/" + }, + "qualificationScope": { + "checksSha256": "b9d7acf0749c3310b680e9376cc4e931cf59382da420a64a4c5e2bf320e89b88", + "executableSha256": "8361afc1146cd380285ecc5e8ad0f0bad7fb056c444d7439acd4611ec40914af", + "kind": "mutation", + "mutationSha256": "fa3eebc80b98440c0042edb79a99701c044e9d85948a231e36cdc2cd298c5858", + "recipe": { + "contentSha256": "53fbb8093b2335837d88c246f04da99858c40b57ce24d17fbd2b6c815abdb62d", + "id": "ecommerce.progression-catalog" + }, + "schemaVersion": 3, + "stack": { + "id": "spacetime", + "reference": { + "id": "ecommerce-reference-spacetime", + "sourceSha256": "7ba1f548e89f461b95b5caf843b0fbcf2b81278428d02869d7f47e1a199eaf6e" + }, + "version": "1.4.0" + }, + "sha256": "265fdedd8dc653c511c334bf716923804657f2558df5685a95873b37c4906663" + }, + "mutationControl": true, + "runs": [ + { + "repetition": 1, + "output": "spacetime-targeted.runs/r1", + "durationMs": 108768, + "processError": null, + "harnessSha256Before": "8cf33debdb3c7f4797c0b324facba96dd68ca68736c60170d61f7b76f892b9e4", + "harnessSha256After": "8cf33debdb3c7f4797c0b324facba96dd68ca68736c60170d61f7b76f892b9e4", + "ok": true, + "failures": [], + "runId": "ecommerce-spacetime-run0-20260918002258-bfb84101", + "score": "2/2", + "imageId": "sha256:32ff9a9e519ba9d1af2fe72f24622caa8ca7a9f2baf2338c6b1e0435e6ac5455", + "criteria": 1, + "zeroPointCriteria": 0, + "fingerprint": "f1da4e8dbf9629a97b00bb384d6cc95f9a0005fccc9fde991cd1f69b79f8de8d", + "outcome": "passed", + "packRuntime": { + "schemaVersion": 1, + "metric": "pack-check-wall-clock-sum-v1", + "packs": [ + { + "id": "ecommerce.progression.review-access-specifications", + "checkCount": 1, + "setupRuntimeMs": 465, + "criterionRuntimeMs": 7234, + "measuredRuntimeMs": 7699, + "budget": { + "status": "bounded", + "maxRuntimeMs": 82000 + }, + "exceeded": false + } + ] + }, + "mutations": { + "caught": 2, + "completed": 2, + "total": 2, + "remaining": 0 + } + } + ], + "stable": true, + "sameImage": true, + "sameHarness": true, + "harnessSha256": "8cf33debdb3c7f4797c0b324facba96dd68ca68736c60170d61f7b76f892b9e4", + "qualifiedCheckKeys": [ + "ecommerce.progression.review-access-specifications.review-eligibility-direct.618a" + ], + "featureCatalog": { + "contentSha256": "8671f7883c2e5a24474a546ef1517407cd9334258e1a7cfe91e292a9af1952f2", + "id": "ecommerce.questlines" + }, + "diagnostic": true, + "ok": true + } +} diff --git a/tools/stack-bench/reference-apps/README.md b/tools/stack-bench/reference-apps/README.md new file mode 100644 index 00000000000..eab672cee53 --- /dev/null +++ b/tools/stack-bench/reference-apps/README.md @@ -0,0 +1,135 @@ +# Reference applications + +Reference applications validate the grader. They are simple, auditable fixtures, +not product examples or recommended application designs. + +`registry.json` is the source of truth for fixture identity, source, and supported +recipes. Qualification evidence proves whether an exact source is usable. + +One cumulative source tree can serve several recipes when each registry entry +binds the same source hash. Qualification evidence remains separate for each +recipe and calibration. + +## Qualification requirements + +A fixture must satisfy all of these conditions before it qualifies a run: + +1. Dependencies install from committed lockfiles in the benchmark build image. +2. The app starts in Docker with run-specific ports and database or module names. +3. Every required scored and supporting check passes for the exact recipe. +4. The source contains no secrets, generated bindings, build output, + transcripts, grader output, or mutation backups. +5. Each mutation has an exact source anchor and produces the intended conclusive + failure without unrelated failures. +6. The registry records the qualified source hash. + +Compile success or an old full score does not promote a fixture. + +## Compile fixtures + +Run the model-free Docker compile check from `tools/stack-bench`: + +```bash +npm run test:references +``` + +Compile one changed fixture with: + +```bash +npm run test:references -- --fixture +``` + +The command copies source into a temporary workspace. It does not edit the +registered fixture. Compile success is not live grading evidence. + +## Live qualification + +Use a configured Linux appliance controller with immutable image identities. +Read the selected calibration before launch. Set the recipe, depth, and repetition +count explicitly; the command defaults are not the calibration policy. For example, +the dependency L3 reference command has this shape: + +```bash +node dist/src/references/reference-live.js --backend \ + --track ecommerce --level 3 --recipe ecommerce.progression-catalog \ + --feature-catalog progression/ecommerce.json \ + --repetitions --out +``` + +The qualifier binds the exact recipe, fixture, source, engine, image, stack, +runner, and check identities. It also verifies lease and resource cleanup. + +`referenceRepetitions` and `mutationRepetitions` come from the selected +[calibration](../tracks/ecommerce/composition/calibrations/). Registered evidence +must match these counts exactly. Extra repeated runs are useful stability +diagnostics, but cannot be substituted for an artifact with a different declared +repetition count. Two clean passes do not prove the absence of intermittent failures. + +For mutation evidence, combine `--mutations` with either `--mutation-id ` +or `--full-mutations`. The qualifier first +checks the clean baseline, then applies each selected defect through the same +isolated Docker lifecycle. + +During development, select only affected defects with `--mutation-id `. +Targeted output is diagnostic evidence. Use `--full-mutations` only when the +complete defect set is required. + +Targeted evidence can qualify a defined slice of an unchanged check population. +Each calibration evidence entry then declares `slice.checks` and a hash-pinned +`slice.snapshot` path. Qualifiers save the recipe hash inputs, calibration and +mutation inputs beside their output as `.inputs.json`. Preserve these +files with the original artifacts. Reconstructed older inputs must reproduce +the identities in the original evidence; a list of unchanged check IDs is not proof. + +The compiler verifies scenario setup, shared inputs, pack budgets, references, +runner, repetition policy and applicable defect definitions. Every required +check must have exactly one reference, mutation and null coverage entry per +required stack/repetition. It rejects missing or overlapping coverage. A targeted +mutation gate may also supply its verified clean baseline for reference coverage. +It retains the artifact's original identities and diagnostic label. + +This reuse path supports independently reset dependency scenarios with the same +qualification policy and population. Sequential inherited-stage evidence is not +supported. Changed executable hashes require a reviewed `qualificationReuse` +decision with retained supporting evidence. An unchanged commit label alone is +not sufficient. If any required input or coverage is missing, keep the candidate +unqualified and run only the missing scope; do not substitute a successful summary. + +For full mutation qualification, use the same scope, add +`--mutations --full-mutations`, set `--repetitions` to `mutationRepetitions`, and +choose a new output path. The runner can emit a companion clean-reference artifact +when the baseline repetition count also matches `referenceRepetitions`. +`--mutation-workers` runs independent defect controls with separate leases; it +does not change the selected checks or their pass rules. +The qualification status command generates commands for up to eight workers by +default. Use `qualification status ... --mutation-workers <1-8>` to select fewer. + +The matching dependency L3 empty-app control is: + +```bash +node dist/commands/null-control.js --track ecommerce --level 3 \ + --recipe ecommerce.progression-catalog --out +``` + +Add repeated `--selected-check ` options to run only the affected +null controls. The keys must belong to the calibration's selected checks. + +A scored check must fail conclusively on the empty app. Zero awarded points alone +are insufficient if the result is a harness failure or inconclusive. Check the +artifact's failure reasons, not only its process exit code. Reference, mutation, +and null runs make no model calls, but still consume local compute. Obtain +authorization before starting these long-running gates. + +Inspect the exact selected definition with: + +```bash +node dist/commands/qualification-cli.js status --track ecommerce --level 3 \ + --recipe ecommerce.progression-catalog +``` + +Static target coverage, a build pass, and historical reports cannot replace +matching live evidence. Preserve failed artifacts and write corrections to new +paths. Never edit old results to match a changed source or calibration. + +Do not edit a registered reference during qualification. A changed source hash +requires new evidence. diff --git a/tools/stack-bench/reference-apps/ecommerce/mongodb/client/index.html b/tools/stack-bench/reference-apps/ecommerce/mongodb/client/index.html new file mode 100644 index 00000000000..8b77d8835cc --- /dev/null +++ b/tools/stack-bench/reference-apps/ecommerce/mongodb/client/index.html @@ -0,0 +1,12 @@ + + + + + + Storefront + + +
+ + + diff --git a/tools/stack-bench/reference-apps/ecommerce/mongodb/client/package-lock.json b/tools/stack-bench/reference-apps/ecommerce/mongodb/client/package-lock.json new file mode 100644 index 00000000000..1c05ce6c7c3 --- /dev/null +++ b/tools/stack-bench/reference-apps/ecommerce/mongodb/client/package-lock.json @@ -0,0 +1,1046 @@ +{ + "name": "client", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "client", + "version": "1.0.0", + "dependencies": { + "react": "^18.3.1", + "react-dom": "^18.3.1", + "socket.io-client": "^4.7.5" + }, + "devDependencies": { + "@types/react": "^18.3.3", + "@types/react-dom": "^18.3.0", + "@vitejs/plugin-react": "^6.1.0", + "typescript": "^5.5.3", + "vite": "^8.2.2" + } + }, + "node_modules/@oxc-project/types": { + "version": "0.146.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.146.0.tgz", + "integrity": "sha512-XC0QsnnhVe7sLIWmYmdPw7x5P0h4W8vUU3Nv1ySgWXtvCz8NizoAEpGXA0sOYoJQV2Rl13LgURAHQ5cI5ILCSA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, + "node_modules/@rolldown/binding-android-arm-eabi": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm-eabi/-/binding-android-arm-eabi-1.2.5.tgz", + "integrity": "sha512-DLe/i+l8ynIBY7XEQ191TeZvCoowIGa18R+dIV30GW7DiOtp74i/xX8hs8GUjW5ARV7VZuie3d6AumSmCwbeRA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.5.tgz", + "integrity": "sha512-zXcwKlQApYAOELHd8PwKDFkagYF9Wy4e0RJ+0qnzl9Pjnpj75TEG8ufv40p2J7kCEfwZAsNiuzRIyNNMWT38ig==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.5.tgz", + "integrity": "sha512-dK4QakI42nzWgJT5sm4y4y/O//D4OxM75/cH28RLV+nzIN9AY+YsbuUVrUTjlLjXR6vpyxFbSsbmNuJ6BP9sww==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.5.tgz", + "integrity": "sha512-fqSALaUu1Wjd1nK2uW2kJDWdLCc8lx1IcY+MTY26Aurfdx19anlzhqXOgCFbBFQnlFDTn4TC1/7Nz4Bl2mLP3A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.5.tgz", + "integrity": "sha512-/vCnNxlkxs9tKxNDcyWUePpJ/PgTzxIaVhoM5SmG8UV+GR/IcPam4VYxi7GIMo7PSDuNqlJqvprqii9NqqVCMw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.5.tgz", + "integrity": "sha512-abk0NLA519LxRCszmbE0jYKuQ9YPocOXTiOXOo6Yr+YAT95VH+PtqYAjOJvGKt3viEd/x4qzabAlwd5bHOOARg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.5.tgz", + "integrity": "sha512-Y7eALiJ8lr0M2HH103Js+g7V34wf6snlpZLAsHI90uLhr3PVlNsbFVAXJC9d/V6BnPyKtpSwI+NcB/RLxsQxuA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.5.tgz", + "integrity": "sha512-xMvZgnbZg4YVnR/AX2b3oOPDTFYJvUVaJg5FedA/LuvexAtXibZQej4cnTkw3rjsJ/ggUROB64TdtETiim+FYA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.5.tgz", + "integrity": "sha512-GRjeqTUDHTo5GwntsLaAMcBahG3nlpjftXWZLN73HiYQlhwEowvarFgQnRnQZtIp4keXX7quXFbG38uPZBa2EA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.5.tgz", + "integrity": "sha512-vLNTR45F2Uwc8AufkNXPmB4VliaXs+FvcheEogIzOXzO4l+LzieXF5A/TWxLy5HtqpsRCHUfd0lPVrrdgXdLHQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.5.tgz", + "integrity": "sha512-Mgj59/HTuYeK9Gz2MA+mBWKnHsAgkBSec15ZMb1st3oIfFbX7gCjOae7GydHhzcyQi9Z/7M1QuN9bR3oFqF0jQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.5.tgz", + "integrity": "sha512-mY8AP0/ichsbhAxGnLa3d3+MwV0EfgrPND2bplI3Ym8T6R2pJ0N87bvrKVwNXmdy3jnr6eQBecdqx/HMknBmpA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.5.tgz", + "integrity": "sha512-8SLssA2oweAxyRgDp789ACfRb/3P+zNRJpzZxSizxF9m8NUDQ4+3xjo8ttjhVGGw6Qxb70oZiEtIjaKikCO7Yw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.5.tgz", + "integrity": "sha512-vGbruD5zquhoc8D9SViXgN2FBJtNdTyQ4DtG+SWiEGlJiAzoKcZ2xp+xuXCffhubVdt0NJlTZqkeRuERy7g8Cw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.5.tgz", + "integrity": "sha512-e/SXpgISz+IoqVcSSI0rx/d/he8zqLex+/rCWpnHpmVfmPIUjag9H6P7zotf0gJHwPUhQxZ/mF8tr6acebT9yw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", + "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@socket.io/component-emitter": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", + "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==", + "license": "MIT" + }, + "node_modules/@types/prop-types": { + "version": "15.7.15", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", + "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "18.3.31", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.31.tgz", + "integrity": "sha512-vfEqpXTvwT91yhmwdfouStN2hSKwTvyRs8qpLfADyrq/kxDw0hZM7Wk9Ug1FELj8hIby+S/+kQCSRFF32nv2Qw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "18.3.7", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz", + "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^18.0.0" + } + }, + "node_modules/@vitejs/plugin-react": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.1.0.tgz", + "integrity": "sha512-qd2BzUBehkov86WFhg0JkEFEYyCLG9uPCe6qWTY/kRlss9OvJrOF2UbIWT7p+8IzZHkEu0DNGHc4HSv+JdDLsw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rolldown/pluginutils": "^1.0.1" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "@rolldown/plugin-babel": "^0.1.7 || ^0.2.0", + "babel-plugin-react-compiler": "^1.0.0", + "oxc-transform-react": "^0.145.0", + "vite": "^8.0.0" + }, + "peerDependenciesMeta": { + "@rolldown/plugin-babel": { + "optional": true + }, + "babel-plugin-react-compiler": { + "optional": true + }, + "oxc-transform-react": { + "optional": true + } + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/engine.io-client": { + "version": "6.6.6", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.6.6.tgz", + "integrity": "sha512-iY6QdftLQ9pyiPoX082bpf/u1UewnOaJrtJIF9T0++QB34lZrj0uP+Q/bj8AlUsAxqhnkTV2BS8SBZSxOmoV5Q==", + "license": "MIT", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.4.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.21.0", + "xmlhttprequest-ssl": "~2.1.1" + } + }, + "node_modules/engine.io-parser": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz", + "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/lightningcss": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.33.0.tgz", + "integrity": "sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.33.0", + "lightningcss-darwin-arm64": "1.33.0", + "lightningcss-darwin-x64": "1.33.0", + "lightningcss-freebsd-x64": "1.33.0", + "lightningcss-linux-arm-gnueabihf": "1.33.0", + "lightningcss-linux-arm64-gnu": "1.33.0", + "lightningcss-linux-arm64-musl": "1.33.0", + "lightningcss-linux-x64-gnu": "1.33.0", + "lightningcss-linux-x64-musl": "1.33.0", + "lightningcss-win32-arm64-msvc": "1.33.0", + "lightningcss-win32-x64-msvc": "1.33.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.33.0.tgz", + "integrity": "sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.33.0.tgz", + "integrity": "sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.33.0.tgz", + "integrity": "sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.33.0.tgz", + "integrity": "sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.33.0.tgz", + "integrity": "sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.33.0.tgz", + "integrity": "sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.33.0.tgz", + "integrity": "sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.33.0.tgz", + "integrity": "sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.33.0.tgz", + "integrity": "sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.33.0.tgz", + "integrity": "sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.33.0.tgz", + "integrity": "sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.18", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.18.tgz", + "integrity": "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", + "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.26", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.26.tgz", + "integrity": "sha512-u82N74LFzG8ca+dD8puPnplTXoGH4fTPpVGuIbt36G3qvNlkvfD0lEAZSxaly3KX8TS/L1A1gsCEmvKmBcVbkQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.17", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/rolldown": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.5.tgz", + "integrity": "sha512-VD2IE5PUG4Oj8zz2VGykiYd5wbnjdIiSsNQb8Qu5B+noEp+A78mu2iVvpp27g8es14Tk9rofNs5Tku9iQCS4fA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oxc-project/types": "=0.146.0", + "@rolldown/pluginutils": "^1.0.0" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm-eabi": "1.2.5", + "@rolldown/binding-android-arm64": "1.2.5", + "@rolldown/binding-darwin-arm64": "1.2.5", + "@rolldown/binding-darwin-x64": "1.2.5", + "@rolldown/binding-freebsd-x64": "1.2.5", + "@rolldown/binding-linux-arm-gnueabihf": "1.2.5", + "@rolldown/binding-linux-arm64-gnu": "1.2.5", + "@rolldown/binding-linux-arm64-musl": "1.2.5", + "@rolldown/binding-linux-ppc64-gnu": "1.2.5", + "@rolldown/binding-linux-s390x-gnu": "1.2.5", + "@rolldown/binding-linux-x64-gnu": "1.2.5", + "@rolldown/binding-linux-x64-musl": "1.2.5", + "@rolldown/binding-openharmony-arm64": "1.2.5", + "@rolldown/binding-win32-arm64-msvc": "1.2.5", + "@rolldown/binding-win32-x64-msvc": "1.2.5" + } + }, + "node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/socket.io-client": { + "version": "4.8.3", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.8.3.tgz", + "integrity": "sha512-uP0bpjWrjQmUt5DTHq9RuoCBdFJF10cdX9X+a368j/Ft0wmaVgxlrjvK3kjvgCODOMMOz9lcaRzxmso0bTWZ/g==", + "license": "MIT", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.4.1", + "engine.io-client": "~6.6.1", + "socket.io-parser": "~4.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-parser": { + "version": "4.2.7", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.7.tgz", + "integrity": "sha512-IH/iSeO9T6gz1KkFleGDWkG9N3dl4jXVYUtMhIqH10Md0ttMer8nUNWiP1DKuNrybD2xBrixLJdCC9J6ECoYkg==", + "license": "MIT", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.4.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/vite": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.2.2.tgz", + "integrity": "sha512-cFKLV/PRgAUlIRm5WjMjJ86jrftzpqcgH+Us+DS8mI3CDNiH30Whrz8uHL3+MOLPAgqbMBAqWdAHAphOAM+z/Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "lightningcss": "^1.33.0", + "picomatch": "^4.0.5", + "postcss": "^8.5.26", + "rolldown": "~1.2.4", + "tinyglobby": "^0.2.17" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.4.0 || ^0.5.0", + "esbuild": "^0.27.0 || ^0.28.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "@vitejs/devtools": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/ws": { + "version": "8.21.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.3.tgz", + "integrity": "sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xmlhttprequest-ssl": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.1.2.tgz", + "integrity": "sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ==", + "engines": { + "node": ">=0.4.0" + } + } + } +} diff --git a/tools/stack-bench/reference-apps/ecommerce/mongodb/client/package.json b/tools/stack-bench/reference-apps/ecommerce/mongodb/client/package.json new file mode 100644 index 00000000000..4817027566c --- /dev/null +++ b/tools/stack-bench/reference-apps/ecommerce/mongodb/client/package.json @@ -0,0 +1,23 @@ +{ + "name": "client", + "version": "1.0.0", + "private": true, + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview" + }, + "dependencies": { + "react": "^18.3.1", + "react-dom": "^18.3.1", + "socket.io-client": "^4.7.5" + }, + "devDependencies": { + "@types/react": "^18.3.3", + "@types/react-dom": "^18.3.0", + "@vitejs/plugin-react": "^6.1.0", + "typescript": "^5.5.3", + "vite": "^8.2.2" + } +} diff --git a/tools/stack-bench/reference-apps/ecommerce/mongodb/client/src/App.tsx b/tools/stack-bench/reference-apps/ecommerce/mongodb/client/src/App.tsx new file mode 100644 index 00000000000..0305f580984 --- /dev/null +++ b/tools/stack-bench/reference-apps/ecommerce/mongodb/client/src/App.tsx @@ -0,0 +1,1482 @@ +import React, { useEffect, useMemo, useRef, useState, useCallback } from "react"; +import { io, Socket } from "socket.io-client"; +import { ProgressionPanel } from "./ProgressionPanel"; +import { BundlePanel } from "./BundlePanel"; +import { CreditPanel } from "./CreditPanel"; +import { SubscriptionPanel } from "./SubscriptionPanel"; + +const TOKEN_KEY = "mongodb_shop_token"; +const CATALOG_PAGE_SIZE = 10; + +interface ItemT { + id: string; + name: string; + price: number; + description?: string; + category: string; + stock: number; + purchaseCount: number; + variants?: string[]; +} + +interface ReviewT { + id: string; + itemId: string; + userId: string; + username: string; + rating: number; + comment: string; + createdAt: string; +} + +interface ItemDetailT { + id: string; + name: string; + price: number; + description: string; + stock: number; + reviews: ReviewT[]; + average: number; +} + +interface CartLineT { + isBundle?: boolean; + itemId: string; + name: string; + price: number; + stock: number; + quantity: number; + reservationSeconds?: number; + expired?: boolean; +} + +interface CartT { + items: CartLineT[]; + total: number; + promotionCode?: string; + discount?: number; +} + +interface OrderLineT { + isBundle?: boolean; + itemId: string; + name: string; + price: number; + quantity: number; + returned?: boolean; + warehouseNames?: string[]; +} + +interface OrderT { + id: string; + items: OrderLineT[]; + total: number; + status: "pending" | "shipped" | "delivered" | "cancelled" | "refunded"; + discount?: number; + creditMinor?: number; + externalMinor?: number; + refundTotal?: number; + createdAt: string; + payments?: Array<{ id: string; amount: number; status: string }>; +} + +interface UserT { + id: string; + username: string; + isAdmin: boolean; + isStaff: boolean; + roles?: string[]; +} + +interface AdminLocationT { + id: string; + itemId: string; + itemName: string; + warehouseId: string; + warehouseName: string; + quantity: number; +} + +interface CategoryTotalT { + category: string; + units: number; + revenue: number; +} + +interface AdminOverviewT { + items: Array<{ id: string; name: string; price: number; stock: number; category: string }>; + warehouses: Array<{ id: string; name: string; total: number }>; + locations: AdminLocationT[]; + revenue: number; + categories: CategoryTotalT[]; + lowStock: Array<{ id: string; name: string; stock: number }>; + queueDepth: number; +} + +interface FulfilmentQueueT { + orders: OrderT[]; + depth: number; +} + +function useTransientError(): [string, (msg: string) => void] { + const [message, setMessage] = useState(""); + const timer = useRef | null>(null); + const show = useCallback((msg: string) => { + setMessage(msg); + if (timer.current) clearTimeout(timer.current); + timer.current = setTimeout(() => setMessage(""), 5000); + }, []); + return [message, show]; +} + +async function apiFetch(path: string, token: string | null, options: RequestInit = {}) { + const headers: Record = { "Content-Type": "application/json" }; + if (token) headers.Authorization = `Bearer ${token}`; + const res = await fetch(path, { ...options, headers: { ...headers, ...(options.headers as any) } }); + const data = await res.json().catch(() => ({})); + if (!res.ok) throw new Error(data.error || "Request failed"); + return data; +} + +export default function App() { + const [token, setToken] = useState(() => localStorage.getItem(TOKEN_KEY)); + const [currentUser, setCurrentUser] = useState(null); + const [initializing, setInitializing] = useState(true); + const [items, setItems] = useState([]); + const [searchQuery, setSearchQuery] = useState(""); + const [categoryFilter, setCategoryFilter] = useState(""); + const [minimumPrice, setMinimumPrice] = useState(""); + const [maximumPrice, setMaximumPrice] = useState(""); + const [inStockOnly, setInStockOnly] = useState(false); + const [searchPage, setSearchPage] = useState(0); + const [cart, setCart] = useState({ items: [], total: 0 }); + // Keep floating panels mutually exclusive so navigation remains reachable. + const [activeView, setActiveView] = useState<"cart" | "orders" | "admin" | "fulfilment" | null>(null); + const cartOpen = activeView === "cart"; + const ordersOpen = activeView === "orders"; + const [orders, setOrders] = useState([]); + const adminOpen = activeView === "admin"; + const [adminOverview, setAdminOverview] = useState(null); + const fulfilmentOpen = activeView === "fulfilment"; + const [fulfilmentQueue, setFulfilmentQueue] = useState({ orders: [], depth: 0 }); + const [recommended, setRecommended] = useState([]); + const [selectedItemId, setSelectedItemId] = useState(null); + const [itemDetail, setItemDetail] = useState(null); + + const [buyError, showBuyError] = useTransientError(); + const [orderError, showOrderError] = useTransientError(); + const [promotionCode, setPromotionCode] = useState(""); + const [promotionError, setPromotionError] = useState(""); + + const socketRef = useRef(null); + + const saveSession = (tok: string, user: UserT) => { + localStorage.setItem(TOKEN_KEY, tok); + setToken(tok); + setCurrentUser(user); + }; + + const clearSession = () => { + localStorage.removeItem(TOKEN_KEY); + setToken(null); + setCurrentUser(null); + setCart({ items: [], total: 0 }); + setOrders([]); + setAdminOverview(null); + setFulfilmentQueue({ orders: [], depth: 0 }); + setActiveView(null); + }; + + const refreshItems = useCallback(async () => { + const data = await apiFetch("/api/items", null); + setItems(data.items); + }, []); + + const refreshCart = useCallback(async (tok: string) => { + const data = await apiFetch("/api/cart", tok); + setCart(data); + }, []); + + useEffect(() => { + if (!token || cart.items.length === 0) return; + const timer = setInterval(() => refreshCart(token).catch(() => undefined), 1000); + return () => clearInterval(timer); + }, [token, cart.items.length, refreshCart]); + + const refreshAdmin = useCallback(async (tok: string) => { + const data = await apiFetch("/api/admin/overview", tok); + setAdminOverview(data); + }, []); + + const refreshFulfilment = useCallback(async (tok: string) => { + const data = await apiFetch("/api/fulfilment/queue", tok); + setFulfilmentQueue(data); + }, []); + + const refreshRecommended = useCallback(async (tok: string | null) => { + const data = await apiFetch("/api/recommended", tok); + setRecommended(data.items); + }, []); + + // Initial load: restore session, fetch the live catalogue, and (if signed + // in) the account's cart. A page opened fresh always asks for current + // numbers rather than trusting anything cached. + useEffect(() => { + let cancelled = false; + (async () => { + try { + await refreshItems(); + } catch (err) { + console.error(err); + } + const tok = localStorage.getItem(TOKEN_KEY); + if (tok) { + try { + const me = await apiFetch("/api/auth/me", tok); + if (!cancelled) { + setCurrentUser(me.user); + await refreshCart(tok); + if (me.user.isAdmin) await refreshAdmin(tok); + if (me.user.isStaff || me.user.isAdmin) await refreshFulfilment(tok); + await refreshRecommended(tok); + } + } catch { + clearSession(); + } + } else { + await refreshRecommended(null).catch((err) => console.error(err)); + } + if (!cancelled) setInitializing(false); + })(); + return () => { + cancelled = true; + }; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + // Socket connection follows the current token. On every (re)connect — + // including after the server was down and the page never reloaded — pull a + // fresh snapshot instead of trusting whatever events were missed. + useEffect(() => { + const socket = io({ auth: token ? { token } : {} }); + socketRef.current = socket; + + socket.on("connect", () => { + refreshItems().catch((err) => console.error(err)); + if (token) { + refreshCart(token).catch((err) => console.error(err)); + } + }); + + socket.on("items:update", (data: ItemT[]) => setItems(data)); + socket.on("cart:update", (data: CartT) => setCart(data)); + socket.on("admin:update", (data: AdminOverviewT) => setAdminOverview(data)); + socket.on("orders:update", (data: OrderT[]) => setOrders(data)); + socket.on("fulfilment:update", (data: FulfilmentQueueT) => setFulfilmentQueue(data)); + socket.on("recommended:update", (data: ItemT[]) => setRecommended(data)); + socket.on("progression:update", () => { + refreshItems().catch((err) => console.error(err)); + refreshRecommended(token).catch((err) => console.error(err)); + if (token) { + refreshCart(token).catch((err) => console.error(err)); + apiFetch("/api/orders", token).then(data => setOrders(data.orders)).catch(() => undefined); + } + }); + socket.on("reviews:update", (payload: { itemId: string; reviews: ReviewT[]; average: number }) => { + setItemDetail((prev) => (prev && prev.id === payload.itemId ? { ...prev, reviews: payload.reviews, average: payload.average } : prev)); + }); + + return () => { + socket.disconnect(); + }; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [token]); + + useEffect(() => { + if (currentUser?.isAdmin && token) { + refreshAdmin(token).catch((err) => console.error(err)); + } + if ((currentUser?.isStaff || currentUser?.isAdmin) && token) { + refreshFulfilment(token).catch((err) => console.error(err)); + } + }, [currentUser, token, refreshAdmin, refreshFulfilment]); + + useEffect(() => { + if (!selectedItemId) { + setItemDetail(null); + return; + } + let cancelled = false; + apiFetch(`/api/items/${selectedItemId}`, token) + .then((data) => { + if (!cancelled) setItemDetail(data.item); + }) + .catch((err) => console.error(err)); + return () => { + cancelled = true; + }; + }, [selectedItemId, token]); + + // Escape closes whichever overlay is open. + useEffect(() => { + const onKeyDown = (e: KeyboardEvent) => { + if (e.key !== "Escape") return; + if (selectedItemId) setSelectedItemId(null); + else if (activeView) setActiveView(null); + }; + window.addEventListener("keydown", onKeyDown); + return () => window.removeEventListener("keydown", onKeyDown); + }, [selectedItemId, activeView]); + + const handleSignUp = async (username: string, password: string) => { + const data = await apiFetch("/api/auth/signup", null, { method: "POST", body: JSON.stringify({ username, password }) }); + saveSession(data.token, data.user); + }; + + const handleSignIn = async (username: string, password: string) => { + const data = await apiFetch("/api/auth/signin", null, { method: "POST", body: JSON.stringify({ username, password }) }); + saveSession(data.token, data.user); + }; + + const handleSignOut = () => { + clearSession(); + }; + + const handleBuyNow = async (itemId: string) => { + try { + await apiFetch(`/api/items/${itemId}/buy`, token, { method: "POST" }); + } catch (err: any) { + showBuyError(err.message); + } + }; + + const handleAddToCart = async (itemId: string) => { + try { + const data = await apiFetch("/api/cart", token, { method: "POST", body: JSON.stringify({ itemId, quantity: 1 }) }); + setCart(data); + } catch (err: any) { + showBuyError(err.message); + } + }; + + const handleQuantityChange = async (itemId: string, quantity: number) => { + try { + const data = await apiFetch(`/api/cart/${itemId}`, token, { method: "PATCH", body: JSON.stringify({ quantity }) }); + setCart(data); + } catch (err: any) { + showBuyError(err.message); + } + }; + + const handleRemove = async (itemId: string) => { + try { + const data = await apiFetch(`/api/cart/${itemId}`, token, { method: "DELETE" }); + setCart(data); + } catch (err: any) { + showBuyError(err.message); + } + }; + + const handleCheckout = async () => { + try { + await apiFetch("/api/checkout", token, { method: "POST" }); + } catch (err: any) { + showBuyError(err.message); + } + }; + + const handleApplyPromotion = async () => { + setPromotionError(""); + try { + const data = await apiFetch("/api/progression/cart/promotion", token, { + method: "POST", body: JSON.stringify({ code: promotionCode }), + }); + setCart((value) => ({ ...value, promotionCode: data.promotion.code, + discount: data.promotion.discount })); + } catch (err: any) { + setPromotionError(err.message); + } + }; + + const openOrders = async () => { + setActiveView("orders"); + if (token) { + try { + const data = await apiFetch("/api/orders", token); + setOrders(data.orders); + } catch (err) { + console.error(err); + } + } + }; + + const openAdmin = async () => { + setActiveView("admin"); + if (token) { + try { + await refreshAdmin(token); + } catch (err) { + console.error(err); + } + } + }; + + const openFulfilment = async () => { + setActiveView("fulfilment"); + if (token) { + try { + await refreshFulfilment(token); + } catch (err) { + console.error(err); + } + } + }; + + const [reviewError, setReviewError] = useState(""); + const handleReviewSubmit = async (itemId: string, rating: number, comment: string) => { + setReviewError(""); + try { + const data = await apiFetch(`/api/items/${itemId}/reviews`, token, { + method: "POST", + body: JSON.stringify({ rating, comment }), + }); + setItemDetail(data.item); + } catch (err: any) { + setReviewError(err.message); + } + }; + + const handleRestock = async (itemId: string, warehouseId: string, quantity: number) => { + try { + const data = await apiFetch("/api/admin/restock", token, { + method: "POST", + body: JSON.stringify({ itemId, warehouseId, quantity }), + }); + setAdminOverview(data); + } catch (err: any) { + showBuyError(err.message); + } + }; + + const handleTransfer = async (itemId: string, fromWarehouseId: string, toWarehouseId: string, quantity: number) => { + try { + const data = await apiFetch("/api/admin/transfer", token, { + method: "POST", + body: JSON.stringify({ itemId, fromWarehouseId, toWarehouseId, quantity }), + }); + setAdminOverview(data); + } catch (err: any) { + showOrderError(err.message); + } + }; + + const handlePriceChange = async (itemId: string, price: number) => { + try { + const data = await apiFetch("/api/admin/price", token, { + method: "POST", + body: JSON.stringify({ itemId, price }), + }); + setAdminOverview(data); + } catch (err: any) { + showOrderError(err.message); + } + }; + + const handleShipOrder = async (orderId: string) => { + try { + await apiFetch("/api/fulfilment/ship", token, { + method: "POST", + body: JSON.stringify({ orderId }), + }); + } catch (err: any) { + showOrderError(err.message); + throw err; + } + }; + + const handleCancelOrder = async (orderId: string) => { + try { + const data = await apiFetch(`/api/orders/${orderId}/cancel`, token, { method: "POST" }); + setOrders((prev) => prev.map((o) => (o.id === orderId ? data.order : o))); + } catch (err: any) { + showOrderError(err.message); + } + }; + + const handleReturnItem = async (orderId: string, itemId: string) => { + try { + const data = await apiFetch(`/api/orders/${orderId}/items/${itemId}/return`, token, { method: "POST" }); + setOrders((prev) => prev.map((o) => (o.id === orderId ? data.order : o))); + } catch (err: any) { + showOrderError(err.message); + } + }; + + const filteredItems = useMemo(() => { + const q = searchQuery.trim().toLowerCase(); + const min = minimumPrice === "" ? -Infinity : Number(minimumPrice); + const max = maximumPrice === "" ? Infinity : Number(maximumPrice); + const filtering = Boolean(q || categoryFilter || minimumPrice || maximumPrice || inStockOnly); + return items.filter((it) => (!q || it.name.toLowerCase().includes(q)) + && (!categoryFilter || it.category === categoryFilter) + && it.price >= min && it.price <= max && (!inStockOnly || it.stock > 0)) + .sort((a, b) => (filtering ? 0 : b.purchaseCount - a.purchaseCount) || a.name.localeCompare(b.name)); + }, [items, searchQuery, categoryFilter, minimumPrice, maximumPrice, inStockOnly]); + const searchResults = filteredItems.slice(searchPage * CATALOG_PAGE_SIZE, + searchPage * CATALOG_PAGE_SIZE + CATALOG_PAGE_SIZE); + + const cartCount = cart.items.reduce((s, l) => s + l.quantity, 0); + const selectedItem = items.find((it) => it.id === selectedItemId) || null; + const isCustomer = !!currentUser && !currentUser.isAdmin && !currentUser.isStaff; + + return ( +
+ + token ? refreshCart(token) : Promise.resolve()} /> + + {initializing && ( +
+
+
Connecting to Storefront...
+
+ )} + +
+

+ Storefront +

+ + { setSearchQuery(e.target.value); setSearchPage(0); }} + onKeyDown={(e) => { + if (e.key === "Escape") setSearchQuery(""); + }} + /> +
+
+ + {currentUser && ( + + )} + {currentUser?.isAdmin && ( + + )} + {(currentUser?.isStaff || currentUser?.isAdmin) && ( + + )} + {currentUser ? ( + <> + + {currentUser.username} + + + + ) : ( + + )} +
+
+ +
+
+ {buyError && ( +
+ {buyError} +
+ )} + +
+
+ + { setMinimumPrice(e.target.value); setSearchPage(0); }} /> + { setMaximumPrice(e.target.value); setSearchPage(0); }} /> + +
+

Catalog

+
+
+ {searchResults.map((item) => ( + setSelectedItemId(item.id)} + onBuy={() => handleBuyNow(item.id)} + onAddToCart={() => handleAddToCart(item.id)} + /> + ))} +
+
+
+ + +
+
+ +
+

Recommended for you

+
+ {recommended.length === 0 ? ( +
Nothing recommended yet
+ ) : ( + recommended.map((item, index) => ( +
+ {index + 1} + setSelectedItemId(item.id)} onBuy={() => handleBuyNow(item.id)} + onAddToCart={() => handleAddToCart(item.id)} /> + {currentUser && } +
+ )) + )} +
+
+ token ? refreshCart(token) : Promise.resolve()} /> + {!activeView && (currentUser?.isStaff || currentUser?.isAdmin) && + token ? refreshCart(token) : Promise.resolve()} staffOnly />} +
+ + {selectedItem && ( + { + setSelectedItemId(null); + setReviewError(""); + }} + onBuy={() => handleBuyNow(selectedItem.id)} + onAddToCart={() => handleAddToCart(selectedItem.id)} + onSubmitReview={(rating, comment) => handleReviewSubmit(selectedItem.id, rating, comment)} + /> + )} +
+ +
setActiveView(null)} /> +
+
+

Cart

+ +
+
+ {cart.items.length === 0 ? ( +
+ Your cart is empty +
+ ) : ( + <> + {cart.items.map((line) => ( + handleQuantityChange(line.itemId, qty)} + onRemove={() => handleRemove(line.itemId)} + /> + ))} +
+ setPromotionCode(e.target.value)} placeholder="Promotion code" /> + +
+ {promotionError &&
{promotionError}
} +
+ Total + ${cart.total.toFixed(2)} +
+ + + + )} +
+
+ +
setActiveView(null)} /> +
+
+

Order history

+ +
+ {orderError && ( +
+ {orderError} +
+ )} +
+ {orders.length === 0 ? ( +
You haven't placed any orders yet
+ ) : ( + orders.map((order) => ( +
+
+ {new Date(order.createdAt).toLocaleString()} + {order.items.length > 0 && order.items.every(line => line.returned) ? "returned" : order.status} +
+
{order.items.map(l => {l.name} ×{l.quantity}{l.returned ? " (returned)" : ""} )}
+
+ ${order.total.toFixed(2)} +
+ {Number(order.creditMinor || 0) / 100} + {order.externalMinor ? order.externalMinor / 100 : order.total - Number(order.creditMinor || 0) / 100} +
{Number(order.discount || 0).toFixed(2)}
+
{Number(order.refundTotal || 0).toFixed(2)}
+ {order.items.some(line => line.isBundle) && {Number(order.refundTotal || 0).toFixed(2)}} + {(order.payments ?? []).map((payment) => ( +
+ {payment.status} + {Number(payment.amount).toFixed(2)} +
+ ))} + {Number(order.refundTotal || 0) > 0 &&
{order.items.map(line => line.name).join(", ")}{Math.round(Number(order.creditMinor || 0) * Number(order.refundTotal || 0) / order.total) / 100}{Number(order.refundTotal || 0) - Math.round(Number(order.creditMinor || 0) * Number(order.refundTotal || 0) / order.total) / 100}
} +
+ {["shipped", "delivered"].includes(order.status) && order.items.some(line => line.isBundle && !line.returned) && } + {order.status === "pending" && ( + + )} + {["shipped", "delivered"].includes(order.status) && + order.items + .filter((l) => !l.returned && !l.isBundle) + .map((l) => ( + + ))} +
+
+ )) + )} +
+
+ + {fulfilmentOpen && (currentUser?.isStaff || currentUser?.isAdmin) && ( + setActiveView(null)} + onShip={handleShipOrder} orderError={orderError}> + token ? refreshCart(token) : Promise.resolve()} staffOnly /> + + )} + + {adminOpen && currentUser?.isAdmin && ( + setActiveView(null)} + onRestock={handleRestock} + onTransfer={handleTransfer} + onPriceChange={handlePriceChange} + orderError={orderError} + > + token ? refreshCart(token) : Promise.resolve()} staffOnly /> + + )} +
+ ); +} + +function ItemCard({ + item, + isCustomer, + onOpen, + onBuy, + onAddToCart, + testId = "item-card", +}: { + item: ItemT; + isCustomer: boolean; + onOpen: () => void; + onBuy: () => void; + onAddToCart: () => void; + testId?: string | null; +}) { + const outOfStock = item.stock === 0; + const [submitState, setSubmitState] = useState('idle'); + const requestAlert = async (event: React.MouseEvent) => { + event.stopPropagation(); + setSubmitState('pending'); + try { + await apiFetch('/api/progression/stock-alerts', localStorage.getItem(TOKEN_KEY), + { method: 'POST', body: JSON.stringify({ itemId: item.id }) }); + setSubmitState('succeeded'); + } catch { setSubmitState('failed'); } + }; + return ( +
+
+ {item.name} +
+
+ + ${item.price.toFixed(2)} + +
+
+ 0 && item.stock <= 5 ? " low" : ""}`} data-role="item-stock"> + {item.stock} + + {outOfStock && ( + + Out of stock + + )} +
+ {isCustomer && ( +
e.stopPropagation()}> + + +
+ )} + {(item.variants || []).map(variant => + {variant})} + {isCustomer && outOfStock && } +
+ ); +} + +function ItemDetailPanel({ + item, + detail, + isCustomer, + reviewError, + onClose, + onBuy, + onAddToCart, + onSubmitReview, +}: { + item: ItemT; + detail: ItemDetailT | null; + isCustomer: boolean; + reviewError: string; + onClose: () => void; + onBuy: () => void; + onAddToCart: () => void; + onSubmitReview: (rating: number, comment: string) => void; +}) { + const [rating, setRating] = useState(5); + const [comment, setComment] = useState(""); + const outOfStock = item.stock === 0; + + const submit = (e: React.FormEvent) => { + e.preventDefault(); + onSubmitReview(rating, comment); + setComment(""); + }; + + return ( +
+
+

{item.name}

+ +
+
+ + ${item.price.toFixed(2)} + + 0 && item.stock <= 5 ? "item-stock low" : "item-stock"}> + {item.stock} in stock + +
+ {outOfStock && ( + + Out of stock + + )} +

{detail?.description || "Loading description..."}

+ + {isCustomer && ( +
+ + +
+ )} + +

+ Reviews — average {(detail?.average ?? 0).toFixed(1)} +

+ {!detail || detail.reviews.length === 0 ? ( +
No reviews yet
+ ) : ( + detail.reviews.map((r) => ( +
+
+ {r.username} + {"★".repeat(r.rating)} +
+
{r.comment}
+
+ )) + )} + + {isCustomer && ( +
+ + setComment(e.target.value)} + /> + +
+ )} + {reviewError && ( +
+ {reviewError} +
+ )} +
+ ); +} + +function CartLineRow({ + line, + onQuantityChange, + onRemove, +}: { + line: CartLineT; + onQuantityChange: (qty: number) => void; + onRemove: () => void; +}) { + const [value, setValue] = useState(String(line.quantity)); + + useEffect(() => { + setValue(String(line.quantity)); + }, [line.quantity]); + + const commit = () => { + const qty = Number(value); + if (Number.isInteger(qty) && qty >= 1 && qty !== line.quantity) { + onQuantityChange(qty); + } else { + setValue(String(line.quantity)); + } + }; + + return ( +
+ {line.name} + {line.reservationSeconds || 0} + {line.expired && Expired} + setValue(e.target.value)} + onBlur={commit} + onKeyDown={(e) => { + if (e.key === "Enter") { + e.preventDefault(); + commit(); + } + }} + /> + ${(line.price * line.quantity).toFixed(2)} + +
+ ); +} + +function AuthBox({ + onSignUp, + onSignIn, +}: { + onSignUp: (username: string, password: string) => Promise; + onSignIn: (username: string, password: string) => Promise; +}) { + const [signUpUsername, setSignUpUsername] = useState(""); + const [signUpPassword, setSignUpPassword] = useState(""); + const [signUpError, setSignUpError] = useState(""); + + const [showSignIn, setShowSignIn] = useState(false); + const [signInUsername, setSignInUsername] = useState(""); + const [signInPassword, setSignInPassword] = useState(""); + const [signInError, setSignInError] = useState(""); + + const submitSignUp = async (e: React.FormEvent) => { + e.preventDefault(); + setSignUpError(""); + try { + await onSignUp(signUpUsername.trim(), signUpPassword); + } catch (err: any) { + setSignUpError(err.message); + } + }; + + const submitSignIn = async (e: React.FormEvent) => { + e.preventDefault(); + setSignInError(""); + try { + await onSignIn(signInUsername.trim(), signInPassword); + } catch (err: any) { + setSignInError(err.message); + } + }; + + return ( +
+
+ setSignUpUsername(e.target.value)} + /> + setSignUpPassword(e.target.value)} + /> + + {signUpError && ( +
+ {signUpError} +
+ )} +
+ + {showSignIn && ( +
+ setSignInUsername(e.target.value)} + /> + setSignInPassword(e.target.value)} + /> + + {signInError && ( +
+ {signInError} +
+ )} +
+ )} +
+ ); +} + +function AdminPanel({ + overview, + onClose, + onRestock, + onTransfer, + onPriceChange, + orderError, + children, +}: { + overview: AdminOverviewT | null; + onClose: () => void; + onRestock: (itemId: string, warehouseId: string, quantity: number) => void; + onTransfer: (itemId: string, fromWarehouseId: string, toWarehouseId: string, quantity: number) => void; + onPriceChange: (itemId: string, price: number) => void; + orderError: string; + children?: React.ReactNode; +}) { + const [restockValues, setRestockValues] = useState>({}); + const [globalRestock, setGlobalRestock] = useState({ item: "", warehouse: "", quantity: "" }); + const [priceValues, setPriceValues] = useState>({}); + const [transferValues, setTransferValues] = useState< + Record + >({}); + + if (!overview) { + return ( +
+
+

Admin

+ +
+
Loading admin data...
+
+ ); + } + + const warehouses = overview.warehouses; + + const transferFor = (itemId: string) => + transferValues[itemId] || { from: warehouses[0]?.id || "", to: warehouses[1]?.id || warehouses[0]?.id || "", qty: "" }; + + return ( +
+
+

Admin

+ +
+ + {orderError && ( +
+ {orderError} +
+ )} + +
+ Total revenue: ${overview.revenue.toFixed(2)} +
+ +
+ setGlobalRestock(value => ({ ...value, item: event.target.value }))} /> + setGlobalRestock(value => ({ ...value, warehouse: event.target.value }))} /> + setGlobalRestock(value => ({ ...value, quantity: event.target.value }))} /> + +
+ +
+
+

Items

+ {overview.items.map((it) => { + const transfer = transferFor(it.id); + return ( +
+ {it.name} + {it.stock} +
+ setPriceValues((prev) => ({ ...prev, [it.id]: e.target.value }))} + /> + +
+
+ + + + setTransferValues((prev) => ({ ...prev, [it.id]: { ...transferFor(it.id), qty: e.target.value } })) + } + /> + +
+
+ ); + })} +
+
+

Warehouses

+
+ {overview.warehouses.map((w) => ( + + {w.name} — {w.total} + + ))} +
+

Stock by warehouse

+ {overview.locations.map((loc) => ( +
+ + {loc.itemName} @ {loc.warehouseName} + + {loc.quantity} +
+ setRestockValues((prev) => ({ ...prev, [loc.id]: e.target.value }))} + onKeyDown={(e) => { + if (e.key === "Enter") { + e.preventDefault(); + const qty = Number(restockValues[loc.id]); + if (Number.isInteger(qty) && qty >= 1) { + onRestock(loc.itemId, loc.warehouseId, qty); + setRestockValues((prev) => ({ ...prev, [loc.id]: "" })); + } + } + }} + /> + +
+
+ ))} +
+
+ +
+
+

Low stock

+
+ {overview.lowStock.length === 0 ? ( +
Nothing is running low
+ ) : ( + overview.lowStock.map((it) => ( +
+ {it.name} + {it.stock} +
+ )) + )} +
+
+
+

Category totals

+ {overview.categories.map((c) => ( +
+ {c.category} + {c.units} + ${c.revenue.toFixed(2)} +
+ ))} +
+
+ {children} +
+ ); +} + +function FulfilmentPanel({ + queue, + onClose, + onShip, + orderError, + children, +}: { + queue: FulfilmentQueueT; + onClose: () => void; + onShip: (orderId: string) => Promise; + orderError: string; + children?: React.ReactNode; +}) { + const [submitState, setSubmitState] = useState('idle'); + const ship = async (orderId: string) => { + setSubmitState('pending'); + try { await onShip(orderId); setSubmitState('succeeded'); } + catch { setSubmitState('failed'); } + }; + return ( +
+
+

Fulfilment queue

+ +
+ + {orderError && ( +
+ {orderError} +
+ )} + +
+ Orders waiting: {queue.depth} +
+ + {queue.orders.length === 0 ? ( +
Nothing waiting to ship
+ ) : ( + queue.orders.map((order) => ( +
+
+ {new Date(order.createdAt).toLocaleString()} +
+
{order.items.map((l) => `${l.name} ×${l.quantity}`).join(", ")}
+
+ {order.items.map((l, idx) => ( + + {(l.warehouseNames || []).join(", ") || "Unknown"} + + ))} +
+ +
+ )) + )} + {children} +
+ ); +} diff --git a/tools/stack-bench/reference-apps/ecommerce/mongodb/client/src/BundlePanel.tsx b/tools/stack-bench/reference-apps/ecommerce/mongodb/client/src/BundlePanel.tsx new file mode 100644 index 00000000000..8d731419784 --- /dev/null +++ b/tools/stack-bench/reference-apps/ecommerce/mongodb/client/src/BundlePanel.tsx @@ -0,0 +1,40 @@ +import { request } from './request'; +import { useEffect, useState } from 'react'; + +type Bundle = { id: string; name: string; price: number; components: Array<{ item: string; quantity: number }> }; +export function BundlePanel({ token, canManage, onAdded }: { + token: string | null; canManage: boolean; onAdded: () => Promise; +}) { + const [open, setOpen] = useState(false); + const [bundles, setBundles] = useState([]); + const [name, setName] = useState(''); + const [price, setPrice] = useState(''); + const [componentsJson, setComponents] = useState('[]'); + const [error, setError] = useState(''); + const refresh = async () => setBundles(await request('/api/bundles', token)); + useEffect(() => { if (open) void refresh().catch(error => setError(String(error))); }, [open, token]); + async function write(path: string, body: unknown) { + try { setError(''); await request(path, token, { method: 'POST', body: JSON.stringify(body) }); await refresh(); await onAdded(); } + catch (error) { setError(String(error)); } + } + return
+ + {open &&
+ {error &&

{error}

} + {canManage &&
+ setName(event.target.value)} /> + setPrice(event.target.value)} /> +