scaffoldWorld function

WorldManifest scaffoldWorld({
  1. required String scenario,
  2. required String feature,
  3. required List<DeclaredTouchpointRow> rows,
  4. required int seed,
})

Scaffold a world manifest for scenario from the declared dependency rows: touchpoints (parsed contracts), the time model (seed), certified default latency bands per touchpoint, a default failure-storm schedule (the issue's storm classes for the declared touchpoint shapes), the golden corpus per method, and a default behavior program exercising every method once.

Deterministic: the same rows + scenario + seed always produce byte-identical manifests.

Implementation

WorldManifest scaffoldWorld({
  required String scenario,
  required String feature,
  required List<DeclaredTouchpointRow> rows,
  required int seed,
}) {
  final touchpoints = <WorldTouchpoint>[];
  final latency = <String, WorldLatencyBands>{};
  final storms = <WorldStorm>[];
  final corpus = <String, Map<String, dynamic>>{};
  final behaviors = <WorldBehavior>[];

  for (final row in rows) {
    final family = familyForDependency(row.name);
    final methods = ContractParser.parse(row.contract);
    touchpoints.add(
      WorldTouchpoint(
        name: row.name,
        type: row.type,
        family: family,
        priority: row.priority,
        contract: row.contract,
        methods: methods,
      ),
    );
    latency[row.name] = WorldLatencyBands.certified;

    // The golden corpus: the certified families seed from the #832
    // certified worlds; generic touchpoints get a placeholder the
    // developer refines to their golden data (certification only
    // requires the world can serve the contract).
    final corpusEntry = <String, dynamic>{};
    for (final method in methods) {
      corpusEntry[method.name] = {
        'fixture': _defaultFixtureFor(family, method),
      };
    }
    corpus[row.name] = corpusEntry;

    // Default failure-storm schedule per the declared shape (storms
    // are METHOD-SCOPED so mid-flow failures stay surgical — an auth
    // expiry at signIn must not also fail signOut):
    // - auth touchpoints get an auth-expiry storm mid-flow
    // - write-shaped methods get a network-flap storm then a
    //   partial-write storm
    if (family == 'firebase-auth') {
      storms.add(
        WorldStorm(
          name: 'auth-expiry-mid-flow',
          kind: 'auth-expiry',
          touchpoint: row.name,
          method: 'signIn',
          fromCall: 1,
          toCall: 1,
          failure: const {'type': 'auth', 'code': 'user-token-expired'},
          description:
              'the session expires mid-flow — honest consumers surface '
              'it, never blind-retry it',
        ),
      );
    }
    final writeMethod = methods.where(
      (m) => const {
        'push',
        'save',
        'write',
        'update',
        'create',
        'post',
        'sync',
      }.contains(m.name.toLowerCase()),
    );
    for (final method in writeMethod) {
      storms.add(
        WorldStorm(
          name: 'network-flap-${method.name}',
          kind: 'network-flap',
          touchpoint: row.name,
          method: method.name,
          fromCall: 1,
          toCall: 2,
          failure: const {'type': 'http', 'status': 503},
          description:
              'network flaps over the first two ${method.name} calls — '
              'retry-with-backoff must survive',
        ),
      );
      storms.add(
        WorldStorm(
          name: 'partial-write-${method.name}',
          kind: 'partial-write',
          touchpoint: row.name,
          method: method.name,
          fromCall: 4,
          toCall: 4,
          failure: const {'type': 'partial'},
          description:
              'a half-written ${method.name} response — honest syncs '
              'detect and repair',
        ),
      );
    }

    // Default behavior program: exercise every method once; retry-sync
    // drivers for write-shaped methods (the temporal class), invoke for
    // reads. Write methods get TWO temporal behaviors so the default
    // storm schedule is fully rehearsed: the flap storm (retry survives)
    // and the partial-write storm (detect + repair).
    for (final method in methods) {
      final isWrite = const {
        'push',
        'save',
        'write',
        'update',
        'create',
        'post',
        'sync',
      }.contains(method.name.toLowerCase());
      if (isWrite) {
        behaviors.add(
          WorldBehavior(
            id: '$scenario-${method.name}-retry-sync',
            driver: 'retry-sync',
            touchpoint: row.name,
            method: method.name,
            args: _defaultArgsFor(method),
            maxAttempts: 4,
            backoffBaseMs: 50,
            backoffFactor: 2.0,
          ),
        );
        behaviors.add(
          WorldBehavior(
            id: '$scenario-${method.name}-partial-write-repair',
            driver: 'retry-sync',
            touchpoint: row.name,
            method: method.name,
            args: _defaultArgsFor(method),
            maxAttempts: 3,
            backoffBaseMs: 50,
            backoffFactor: 2.0,
          ),
        );
      } else {
        behaviors.add(
          WorldBehavior(
            id: '$scenario-${method.name}',
            driver: 'invoke',
            touchpoint: row.name,
            method: method.name,
            args: _defaultArgsFor(method),
            maxAttempts: 1,
            expect: family == 'firebase-auth' && method.name == 'signIn'
                ? 'red'
                : 'green',
          ),
        );
      }
    }
  }

  return WorldManifest(
    schema: WorldManifest.schemaVersion,
    spec: WorldManifest.specNumber,
    scenario: scenario,
    feature: feature,
    version: 1,
    seed: seed,
    touchpoints: touchpoints,
    latency: latency,
    storms: storms,
    corpus: corpus,
    behaviors: behaviors,
    description:
        'scaffolded by `zfa simulate init` from the declared dependency '
        'table (issue #960); refine the corpus fixtures, latency bands, '
        'and storm windows to your scenario golden reality',
  );
}