# Create your first portable bug report

This runnable Node example creates an incomplete but useful report, adds observed behavior as a new revision, and exports it with an explicit review policy. No browser, React component, tracker, or server is required.

## Prepare

Want to inspect the revision behavior before setting up Node? [Run the small browser example](../../examples/small-examples.md#keep-identity-while-revising-a-report). It uses supported APIs with authored data; the Node example below additionally exports a portable bundle.

Complete [workspace setup](../../../contributing/workspace.md) and `pnpm build`. Save the following as an `.mjs` file at the repository root so Node resolves the built workspace packages. Run it with the pinned Node runtime (`pnpm exec node your-file.mjs`). Generated report output belongs outside tracked source.

```js
import { mkdir, writeFile } from 'node:fs/promises';
import { join } from 'node:path';
import { createBugReport, reviseBugReport } from '@snagbadger/reporting';
import { createReportBundle } from '@snagbadger/reporting/bundle';

const at = '2026-10-11T12:00:00.000Z';
const initial = createBugReport({
  id: 'profile-save-example',
  at,
  title: 'Saved profile name disappears after navigation',
  expected: {
    text: 'The saved display name survives in-page navigation',
    basis: 'established',
  },
});
const report = reviseBugReport(
  initial,
  {
    actual: 'Save confirmed Morgan Lee; returning showed Alex Morgan',
    steps: [
      {
        id: 'save-and-return',
        instruction:
          'In Buggy save mode, save Morgan Lee, visit Overview, then Profile',
        basis: 'observed',
        verification: 'unverified',
        evidenceIds: [],
        interactionIds: [],
      },
    ],
  },
  '2026-10-11T12:01:00.000Z',
);
const bundle = await createReportBundle(report, {
  exportId: 'profile-export-example',
  at: '2026-10-11T12:02:00.000Z',
  readAttachment: () => null,
  policy: {
    id: 'reviewed-public-example',
    // Only this known, authored example has been manually reviewed.
    reviewReport: (value) => value,
    // Real attachments need a project-owned review before inclusion.
    reviewAttachment: () => ({ action: 'omit' }),
  },
});
const directory = 'dist/first-bug-report';
for (const file of bundle.files) {
  const target = join(directory, file.path);
  await mkdir(join(target, '..'), { recursive: true });
  await writeFile(target, file.content);
}
console.log(
  report.id,
  report.revision,
  bundle.files.map((file) => file.path),
);
```

## Inspect the result

The identity remains `profile-save-example`, and the revision is `2`. Open `dist/first-bug-report/index.html`; inspect `report.json` beside it. The report has no screenshot, executable reproduction, or verified replay claim. Its described steps are authored from the sample observation; running this snippet does not observe a browser.

The source report remains unchanged by export. Export identity and review policy identify a reviewed derivative of revision 2. This example's pass-through narrative review is appropriate only for its known authored text, not arbitrary user reports.

For a prepared fixture with a diagnostic redaction and incidental test comment, use [the generated report example](../../examples/test-results.md). For real data, continue with [sanitization and export](../guides/export-and-sanitize-evidence.md) and [portable report contracts](../../../integration/portable-reports.md).
