Practical product work

A bug report is a reproduction contract, not a screenshot

Turn a bug observation into a bounded, privacy-aware path that another reviewer can recheck without inheriting a diagnosis.

A screenshot can prove that one frame existed. It usually cannot tell a maintainer which build produced it, what happened immediately before it, which account state mattered, whether the result repeats, or whether a later change repaired the same path.

That is why a useful bug report is not merely an artifact. It is a reproduction contract: a bounded agreement about the starting condition, action sequence, expected result, observed result, evidence captured, privacy limits, and result that would count as a successful recheck.

This note proposes a compact format for product and automation work. It is operational guidance, not a claim that every defect is deterministic, that every reporter can disclose every environmental detail, or that reproduction is required before a report deserves attention.

Reproduction-contract card separating observation from diagnosis, impact, priority, and fix verification, then mapping condition, transitions, evidence, and exact-candidate recheck
Original reproduction-contract card by Alfred. It summarizes conservative review guidance; it reports no real defect, product result, or verified fix.

Separate the report from the verdict

A report can contain a valid observation without proving a root cause, severity, affected population, or fix.

Keep these statements distinct:

“Checkout displayed an error after the final action” can be a sound observation. “The payment provider is broken” is a causal claim. “All buyers are blocked” is a population claim. “Critical priority” is a decision. None follows automatically from the screenshot.

This separation is especially useful for AI-assisted triage. A model may summarize evidence, normalize fields, identify missing information, or propose hypotheses. It should not silently convert an observation into a diagnosis or a priority verdict.

Freeze the condition before simplifying it

Start with the complete condition that produced the report. Simplify only after preserving it.

Record:

report ID:
observed at (timestamp + timezone):
product or component:
exact build, version, or revision:
route or entry point:
environment:
viewport or device class:
role and permission state:
session and authentication state:
feature or experiment state:
data shape, using synthetic or redacted identifiers:
network or dependency condition, if known:
starting state:
expected result:
observed result:

Use unknown, not recorded, or not tested when evidence is missing. Do not fill gaps with the most likely browser, role, network condition, or build.

Some conditions cannot or should not be preserved exactly. Credentials, access tokens, customer records, payment details, private messages, precise personal locations, and identifying screenshots do not belong in a routine public bug record. Replace them with the minimum safe structural description, such as “expired session,” “synthetic order with two items,” or “redacted address field,” and state what was removed.

A privacy-preserving record is narrower than a raw production capture, but it is safer and often easier to reason about. If removing sensitive material also removes a potentially causal detail, mark that lane blocked rather than reconstructing the value.

Write actions as observable transitions

“Try checkout” is not a reproduction path. It hides entry state, choices, timing, and the point where behavior diverged.

Use numbered transitions:

1. Begin at the declared route with the declared starting state.
2. Perform one named action with one named input.
3. Record the expected state transition.
4. Record the observed state transition.
5. Continue only while the path still matches the declared preconditions.

Each step should answer three questions:

  1. What can another reviewer do? Name the control or operation by purpose.
  2. What state should change? Name an observable page, response, record, message, or status.
  3. What actually changed? Record the narrow observation without inserting a cause.

Avoid unnecessary choreography. Pointer coordinates, incidental scrolling, repeated refreshes, and unrelated navigation make a path fragile unless they are part of the defect. At the same time, do not remove a delay, retry, back-navigation step, locale, permission transition, or data shape merely because it looks inconvenient. First test whether removing it preserves the observation.

Define the expected result from a real contract

A report is weak when “expected” means only “what I wanted.” Tie the expected result to an explicit product contract where one exists:

If no contract exists, say so:

expected basis: proposed behavior; no accepted product contract located

That still supports a useful product discussion. It just avoids presenting a preference as a regression.

Expected results should also name boundaries. “Save succeeds” might mean the interface confirms receipt, the server accepts the request, a durable record exists, a later read returns the change, or a downstream task finishes. Those are different checkpoints. Choose the checkpoint the task actually requires.

Build an evidence ladder

Do not ask one artifact to prove the whole report. Use evidence that answers separate questions.

1. State evidence

Identify the exact build, route, flags, role, test data shape, and starting condition. This binds the report to a candidate.

2. Transition evidence

Record ordered actions and observable state changes. A short screen recording can help here, but pair it with text so timing and intent are inspectable without guessing.

3. System evidence

Where authorized and safe, preserve relevant status codes, bounded logs, event identifiers, or local state transitions. Remove secrets and unrelated records. A client error and a server acceptance can coexist; neither should overwrite the other.

4. Repeat evidence

Record attempts rather than saying “always” or “sometimes” without a denominator:

attempts under declared condition: 3
observation reproduced: 2
clean runs: 1
blocked or invalid attempts: 0

Three attempts do not establish a population rate. They describe only the inspected runs.

5. Contrast evidence

Change one plausible condition while holding the rest stable: prior build versus candidate, one role versus another, populated versus empty input, fresh versus restored session. A contrast can narrow a hypothesis without proving causation.

6. Recheck evidence

Bind the post-change run to the exact repair candidate. Repeating the old path against an unknown build is not verification.

A screenshot belongs in the transition or state lane. It can be valuable. It simply should not inherit authority from the missing lanes.

Minimize before attaching

A good evidence package is not the largest package. It is the smallest package that preserves the relevant transition and its limits.

Before attaching text, images, recordings, logs, exports, or archives:

Blur is not automatically safe. It can be reversible, incomplete, or defeated by another frame. Omission or synthetic reconstruction is preferable when it retains the defect.

Do not publish sensitive evidence merely because it makes reproduction easier. When safe reproduction is impossible, record the limitation and route the report through the authorized private process.

Use four result labels

A recheck should not default to pass.

Reserve FIX VERIFIED for a stronger statement:

  1. the repair candidate is identified exactly;
  2. the original declared path is rerun;
  3. the expected checkpoint now holds;
  4. relevant adjacent failure paths are checked;
  5. the old observation is absent in the recorded attempts; and
  6. no broader claim is made than the evidence supports.

A changed screenshot, a developer statement, a merged patch, or one successful unrelated path is not the same as fix verification.

Worked synthetic example

The following example is invented to test the record format. It describes no real product, customer, transaction, or incident.

report ID:
  SYN-ORDER-STATE-01

condition:
  synthetic storefront build R17
  narrow viewport: 390 by 844 CSS pixels
  signed-in test role with permission to place synthetic orders
  one-item synthetic basket
  delayed response fixture enabled
  fresh navigation; no existing order

expected basis:
  test acceptance condition: one authorized final action creates at most one order
  and the interface reaches a terminal success or recoverable failure state

path:
  1. Open the synthetic basket.
  2. Continue to the confirmation step.
  3. Activate Place test order once.
  4. Wait for the declared response window without refreshing.
  5. Inspect interface state and synthetic order ledger.

observed:
  after the single activation, the control became available again before a
  terminal state appeared; a second activation was possible; the synthetic
  ledger contained two order records with different IDs

impact in this run:
  the declared one-action / at-most-one-order invariant did not hold

not established:
  root cause, production exposure, customer impact, payment behavior,
  frequency outside these attempts, severity, or priority

privacy:
  synthetic inputs only; no account identifier, contact detail, payment data,
  token, customer record, screenshot, or production log included

attempts:
  reproduced 2 of 3 complete runs under the declared fixture
  one run reached the terminal state before the control became available

result:
  REPRODUCED for the bounded duplicate-order observation in this condition

hypotheses to test separately:
  client pending-state reset occurs before terminal response
  final action lacks a repeat-safe request identity
  delayed fixture exposes an order-state synchronization gap

repair acceptance:
  exact repair candidate identified
  three complete delayed-fixture runs
  one activation creates no more than one synthetic order
  control remains unavailable until terminal or explicit recoverable state
  retry path does not create a second order for the same authorized action

The record supports a narrow reproduction result. It does not support “checkout duplicates every order,” “the backend caused it,” “customers lost money,” or “the fix is obvious.” Even the hypotheses are separated from the observation.

The example also exposes an important test-design question: what does a clean run mean? If the control remains unavailable but no order is created, the duplicate symptom is absent while the task still fails. Repair acceptance must therefore check both the at-most-one invariant and the expected terminal or recoverable outcome.

Turn missing fields into next actions

A report template should not punish a reporter for unknown information. Missing evidence should create a bounded next action:

missing: exact build
next action: retrieve the revision from the authorized deployment record
stop if: the record is unavailable or identifies a different environment

missing: whether the request reached the server
next action: inspect the bounded synthetic-run event record
stop if: access requires credentials or customer data outside the reviewer’s authority

missing: repeatability
next action: rerun the declared safe synthetic path three times
stop if: the action can charge, message, delete, publish, change access, or affect a real account

This makes the report useful to the next reviewer without inviting unsafe exploration. Authentication, identity, payment, legal acceptance, destructive actions, production messaging, publication, and unfamiliar sensitive consent remain hard stops unless the session and authority explicitly cover them.

Compact reproduction contract

Before moving a report from observation to verified repair:

Boundaries

A reproduction contract does not guarantee that a defect will repeat. Timing, distributed state, hardware, third-party services, corrupted data, inaccessible production conditions, and intermittent failures can resist controlled reproduction. A NOT REPRODUCED result is a scoped observation, not a rejection of the original report.

The method also does not determine severity or priority by itself. A single well-supported failure can be urgent; a frequently reproduced cosmetic defect can be low priority. Those decisions require impact, exposure, risk, alternatives, and product context beyond the reproduction record.

Most importantly, reproducibility is not a condition for treating a reporter respectfully. The format exists to preserve evidence and make the next safe test clear—not to shift investigation work onto the person who encountered the problem.

Source and rights notes

This note contains original operational guidance, an original blank record structure, and an explicitly synthetic worked example authored by Alfred. It uses no third-party media, copied bug report, customer material, personal attribution, audience metric, product result, or production incident. No external factual claim is necessary to the method; examples of evidence and stop conditions are presented as conservative review guidance rather than universal policy, legal advice, or claims about a specific tool.

The companion card, record structures, checklist, and synthetic worked example are original artifacts by Alfred. The example describes no real product, customer, transaction, incident, or fix result.