Skip to content

journey-runner.js rung 2 silently skips a span claim that is only negative (ordered: [] + mustNotFire) #150

Closed

Description

@MendixMau

What happens

Rung 2 in project-tests/e2e/journey-runner.js (~l.726) runs only when step.spans.ordered is non-empty:

if (step.spans && step.spans.ordered && step.spans.ordered.length) {
  ...
  for (const n of step.spans.mustNotFire || []) O.assertNotFired(...)
}

mustNotFire is therefore honoured only next to a positive list. A step whose whole proof is "this did NOT run" is one example: Cancel on a "Reset all state?" confirmation, where the reset microflow must not fire and nothing fires at all. Such a step cannot say so.

spans: { ordered: [], mustNotFire: ["ACT_X_Reset"] } is skipped with no output. The journey file reads as if it declares a trace claim, and the claim proves nothing.

Evidence (card-disbursement requirements-driven build, 2026-09-26)

Writing span claims for a 9-step admin-console journey. That step was left with no span claim, and its data rung (rows unchanged) carries the proof.

Why this is not a one-line guard change

With nothing fired, O.capture(t0, {min: 1, …}) returns zero spans. The existing branch then reports INVALID "zero spans captured — Jaeger down or OTel off". So "correctly nothing ran" and "tracing is broken" look the same. A negative-only claim needs a liveness reference:

  • a span the step is known to produce, such as the page's own data-source retrieve or the button's nanoflow; or
  • a Jaeger health/services query taken in the same window.

Suggested fix

  1. Run rung 2 when ordered or mustNotFire is non-empty.
  2. For a negative-only claim, wait the normal capture window (there is nothing to until on). Then assert no match, gated on a liveness check so an empty capture is not read as a pass.
  3. Emit a loud INVALID when a step declares spans that rung 2 will not evaluate, instead of skipping silently.
  4. Add a positive-control mutant that injects the forbidden name into the captured list. --positive-control already has a trace-negative rung (~l.506) that assumes an ordered list; it needs a branch for this.

Files

  • project-tests/e2e/journey-runner.js: rung 2, positive-control trace-negative mutant
  • project-tests/e2e/otel.js: capture
  • skills/testing-shape.md / skills/journey-proof.md: claim shapes

Activity

  1. added 3 commits that reference this issue on Oct 8, 2026
  2. MendixMau commented on Oct 14, 2026

    @MendixMau
    OwnerAuthor

    Fixed by #310, which landed on master in the integration squash #329 (commit 31e90ae) after independent review. Closing; reopen if it still reproduces on master.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions