LLMSkillHub
mirroredCopied from ffroliva/gflow-cli under MIT. ffroliva has not claimed this page, and is not affiliated with LLM SkillHub.

ffroliva / scenario

Pre-implementation edge-case and scenario explorer for gflow-cli. Decomposes a proposed feature or change across 13 structured dimensions specific to gflow-cli's failure surfaces (WAF/reCAPTCHA, Playwright selectors, auth token lifecycle, batch resume, data layer safety, cross-platform paths). Produces a severity-ranked scenario table to feed into the PLAN spec and the test matrix before EXECUTE begins.

0
SKILL.md
12.2 KB

scenario — Edge Case & Scenario Explorer

Systematic pre-implementation scenario analysis. For a given feature or change,
produces a severity-ranked table of test scenarios across 13 dimensions tuned
to gflow-cli's known failure surfaces. Feed the output into PLAN.md tasks and
tests/features/ BDD scenarios before entering EXECUTE mode.


When to invoke

Use before implementing any of:

  • A new generation path (T2V, I2V, R2V, batch manifest runner)
  • Transport changes (any new HTTP call against aisandbox-pa.googleapis.com)
  • Auth or session changes (new strategy, cookie extraction, SAPISIDHASH wiring)
  • Selector cascade changes (ONBOARDING_SELECTORS, NEW_PROJECT_SELECTORS, FRAME_SLOTS_STRUCT, IMAGE_MODEL_OPTION_SELECTORS)
  • Data layer changes (schema migration, new OperationRecorder callsite, redaction change)
  • New CLI subcommand, flag, or exit code

Skip for: pure doc changes, CHANGELOG/version bumps, scripts/ tooling with no production callpath.


Invocation

/gflow:scenario <feature or change description>

<feature or change description> is a brief summary of what you're about to implement. Examples:

  • "SAPISIDHASH auth header wired into _post_json for aisandbox-pa routes"
  • "gflow video batch manifest ledger (skip already-completed rows)"
  • "Image model picker converted from English has-text to structural anchor"
  • "CDP-attach transport as opt-in alongside ui_automation"

The 13 dimensions

For each dimension, enumerate scenarios that are non-obvious — do not list
things that a basic happy-path test already covers. Focus on things that break
in production but pass in unit tests.

D1 — Auth & session lifecycle

The SAPISID cookie expires. The user re-runs gflow auth login mid-batch. A
profile is created but the Flow session was never verified. The session is valid
for labs.google tRPC but not for aisandbox-pa. Two profiles are in use
simultaneously (Chromium profile-lock).

D2 — WAF / reCAPTCHA scoring

A profile's WAF heat score is elevated from prior automation runs. reCAPTCHA
Enterprise detects navigator.webdriver=true despite the --disable-blink-features
stealth flag. The grecaptcha.execute() call times out or returns a challenge
that requires human interaction. The same token is submitted twice (single-use
token reuse). A batch run fires multiple rapid token mints within one session.

D3 — Selector cascade drift & Locale Invariance (Flow UI updates)

Google Flow ships a UI update that renames or restructures a selector anchor.
FRAME_SLOTS_STRUCT matches zero elements (the PR #70 regression). The
structural-first tier matches but selects the wrong element (e.g., two elements
matching div[type='button'][aria-haspopup='dialog'] after Flow adds a new
dialog button). A non-English locale is used (e.g. GFLOW_CLI_LOCALE=pt-BR or a Brazilian Google account) and single-language English text selectors fail because they lack Tier 1 structural anchors (a[href*='changelog'], button:has(i:text('close'))) or Tier 2 multi-locale text cascades. A new locale is used whose CMP dialog is not in
_ONBOARDING_TEXT_SELECTORS. The --lang=en-US Chromium arg is removed before
IMAGE_MODEL_OPTION_SELECTORS is converted to structural anchors.

D4 — Batch manifest & resume

A 50-row TSV manifest dies at row 23 (auth expiry). On resume, rows 1–22 are
re-submitted and double-billed. A row has an empty start_image field (T2V)
while the column parser expected a path. The output path already exists on disk
from a prior run (overwrite vs skip decision). Two gflow video batch invocations
against the same profile run concurrently (Chromium profile-lock).

D5 — Concurrency & Page pool

GFLOW_CLI_CONCURRENCY=16 fans out 16 simultaneous page.evaluate() reCAPTCHA
token mints — do they share site key state safely? A Page is returned to the pool
while still in a modal dialog (state contamination for the next checkout). A
QueueFull double-checkin race where two coroutines both attempt to return the
same Page object. asyncio.gather propagates one failure but leaves the other
coroutines in a half-completed state with no cleanup path.

D6 — Data layer (SQLite / DataStore)

DataStore migration runs on a schema that's one version ahead (newer-schema
detection should raise DataStoreError exit 16, not silently corrupt). An
OperationRecorder.on_started callback raises inside a generation loop — does
the batch continue or crash? GFLOW_CLI_HISTORY_PROMPTS=redacted is set — does
the new callsite respect the redaction gate? A Windows path with a drive letter
is stored in the DB and retrieved on Linux (or vice versa). The DB is on a
network filesystem and the write locks time out.

D7 — Error propagation & exit codes

A new exception class is added but not registered in EXIT_CODE_MAP. A
FlowApiError subclass is raised inside a retry loop — does reraise=True
propagate the right typed exception or does tenacity eat it? WireFormatError
discovery payload logs the route body prefix — does it redact reCAPTCHA tokens
and auth headers? An unhandled exception escapes run_with_handlers — is it
SHA-256-hashed before logging (never raw message)?

D8 — Cross-platform paths

A Windows user has a Unicode character in their %LOCALAPPDATA% path. The
output directory path contains spaces. platformdirs returns a different base
path on macOS vs Linux vs Windows — does the feature hardcode any of these?
PYTHONUTF8=1 is not set — are there cp1252 encoding traps on Windows for
prompt text or file names?

D9 — Transport edge cases

The HTTP response body is valid JSON but has an unexpected top-level key (should
emit WireFormatError with discovery payload, not crash). A video generation
response omits operations[0].operation.name (the omni-flash NULL
flow_operation_id issue). A status-poll response arrives before the listener
is attached (_attach_status_response_listener race). A video download URL has
a googleapis.com host not in the SSRF allowlist.

D10 — Headless vs headed environment

The feature is run in a CI environment with no display server (Linux, no Xvfb).
The Playwright context is launched headed (user has GFLOW_CLI_HEADLESS=false)
and the window is closed manually mid-batch. `gflow auth login --browser
internal` is used on a machine where Playwright bundled Chromium is flagged by
Google's G12 block.

D11 — Input validation & boundary values

A prompt string is 4001 characters (Flow's apparent limit). A manifest TSV has
zero rows (after the header). --seed receives a negative integer or a string.
-n 5 is passed to gflow image t2i (Flow's UI cap is x4). An aspect ratio
of 3:2 is passed (valid-looking but not in the whitelist). A --profile name
contains path-separator characters.

D12 — Observability & structured log contract

A new structlog event is emitted — is its key name stable and documented in
docs/ARCHITECTURE.md? A new error_raised path: does it carry the full RFC
9457 Problem Details shape (type, title, status, detail, instance,
remediation_hint)? correlation_id is bound at the process boundary — does
it propagate into the new code path or is it missing from the event?

D13 — MCP surface parity

gflow ships the same capability twice: as a CLI command and as an MCP tool. Every
edge case above therefore has an MCP twin — enumerate it, because the paths are not
the same code. The MCP tool can run direct or **queued through
worker/codec.py**, so a param that works via the CLI can be accepted and silently
dropped on the queued path. Ask: what does this feature look like invoked as an MCP
tool? Which errors reach the agent as a Problem Details envelope rather than an exit
code? Does the tool's docstring still describe the behaviour truthfully? The six
mirror axes are enumerated once, in skills/check/SKILL.md step 1b — do not restate
them here, scenario's job is only to name the MCP cases that need scenarios.


Artifact location

Write the analysis to docs/superpowers/plans/<YYYY-MM-DD>-<feature-slug>/SCENARIO.md
(same directory the subsequent /gflow:plan writes its PLAN.md into) and commit it
with the plan on the feature branch. Established by the image-upscale (#171) and
locale-selectors (#170) cycles — do not leave the analysis only in conversation.

Output format

# Scenario: <feature short title>

## Coverage map
<Which of the 13 dimensions are relevant for this feature? List active dimensions and why skipped dimensions are skipped.>

## Scenario table

| # | Dimension | Scenario | Severity | Expected behaviour | Test category |
|---|---|---|---|---|---|
| 1 | D2 WAF/reCAPTCHA | WAF score elevated on profile from prior run | Critical | WafRejectionError raised with remediation hint "let score decay or use a different profile"; exit code 403-mapped | E2E live (`@pytest.mark.live`) |
| … | … | … | … | … | … |

Severity: **Critical** (data loss / billed twice / unrecoverable) · **High** (feature broken, workaround exists) · **Medium** (degraded UX, explicit error) · **Low** (cosmetic or edge-only)

Test category: **Unit** (no I/O) · **Integration** (mocked HTTP/Playwright) · **BDD** (Gherkin feature file) · **E2E smoke** (`@pytest.mark.smoke`) · **E2E live** (`@pytest.mark.live`, opt-in)

## Must-cover before merge (Critical + High)
1. …

## Deferred (Medium + Low — log as issues, not blockers)
1. …

## Suggested BDD scenarios

@e2e @e2e_auth
Feature: <feature name>
Scenario: <scenario title>
Given …
When …
Then …


**Tag by surface — the tag is the binding, not decoration.** pytest-bdd turns each
Gherkin tag into a pytest marker, and `addopts`' `-m 'not e2e …'` filters on exactly
that. So the tag decides where the scenario runs and who must run it:

| The scenario can only happen… | Feature-level tags | Bound from |
|---|---|---|
| in a real browser / against real Flow | `@e2e` + one cost tier (`@e2e_auth`, `@e2e_image`, `@e2e_video`, …) | `tests/e2e/test_<slug>_bdd.py` |
| in our own code (parsing, routing, exit codes, redaction) | none | `tests/features/test_<slug>_steps.py` |

One feature file is bound by exactly **one** module — bound twice, its scenarios run
twice. `tests/features/test_e2e_binding_guard.py` enforces this offline in four directions
(orphan, missing tier, untagged live binding, double binding), so an `@e2e` scenario
nobody wrote a test for fails normal CI. Mechanics:
[`docs/E2E_TESTING.md`](../../docs/E2E_TESTING.md) § BDD-bound e2e.

## Known-issues cross-reference
<Any scenario that maps to an existing KNOWN_ISSUES entry — link and note whether the proposed implementation resolves, mitigates, or is blocked by it.>

Integration & Pipeline Continuation (Next Step Handoff)

  1. Run /gflow:predict first to validate the approach (GO/CAUTION/STOP).
  2. Run /gflow:scenario to enumerate edge cases and build the test matrix.
  3. Use the "Must-cover before merge" list as the acceptance criteria for the PLAN.md task.
  4. Add BDD scenarios before coding (TDD is non-negotiable per AGENTS.md), each
    tagged by its surface per the table above — a browser-only scenario is bound from
    tests/e2e/, and a mocked stand-in does not discharge it
    ([`skills/issue-resolve`](../issue-resolve/SKILL.md) § The Bug Lane, step 5).

  5. Next step: Proactively announce: "BDD Scenarios generated. Next step: Phase 4 Implementation Plan (/gflow:plan <feature>)."

Provenance

Adapted from vc-scenario in vibecode-pro-max-kit (assessment 2026-05-28).
13 dimensions re-scoped to gflow-cli's specific failure surfaces: Google WAF/reCAPTCHA, Playwright selector drift, auth token lifecycle, batch resume idempotency, SQLite data layer, RFC 9457 error propagation, cross-platform Windows/macOS/Linux paths.