Workflow

Know when feedback is actually live

Applied means a developer committed a fix. Live means that commit is running on the site. Those are different states, sometimes days apart — and the person who left the comment cares about the second one.

Applied is not live

When pointer apply --mark runs, the comment is recorded as Applied with the commit SHA and a link to the commit. That answers “did anyone act on my feedback?” — not “is the fix on the site?”. The commit still has to be pushed, merged, built, and deployed before the person who left the comment can see it.

Pointer closes that last mile by marking a comment live when a build that contains its commit is reported. Once that happens, the comment card shows a ✓ live pill (with the deployed SHA) instead of completed, and the person who left it knows the fix has actually shipped.

The primary path: pointer status --deployed

From inside the repository that was deployed:

npx pointer-feedback status --deployed [sha]
# sha defaults to HEAD

What it does, in order:

  1. Resolves the deployed SHA with git rev-parse (the argument you pass, or HEAD).
  2. Fetches the project's applied-but-not-yet-deployed comments — comments with a commit SHA and no deploy date yet.
  3. Computes ancestry locally: for each candidate commit, git merge-base --is-ancestor <commitSha> <deployedSha>.
  4. Reports the build to POST /api/projects/<key>/builds with the deployed SHA and the list of contained commit SHAs. The server stamps each matching comment with its deploy date and the build that carried it.

Why the CLI owns this

Reporting from CI

Run the command as the last step of your deploy pipeline, in a checkout of the repository that was just deployed. The project and server come from the committable .pointer/config.json; the API key comes from the environment (POINTER_API_KEY) because .pointer/credentials.env is gitignored and never reaches CI on its own.

# GitHub Actions deploy job
- name: Report deployed build
  run: npx pointer-feedback status --deployed
  env:
    POINTER_API_KEY: ${{ secrets.POINTER_API_KEY }}

Other CI systems are the same shape: a step that runs after the deploy, inside the repository checkout, with POINTER_API_KEY in the environment.

Exit code Meaning
0 Build reported. Prints how many comments were marked deployed.
1 The report could not be read from or sent to the server.
2 The argument is not a commit in this repository, or HEAD could not be read (run it inside the deployed repository).
3 No API key found (missing POINTER_API_KEY).

The secondary path: the widget beacon

If the widget does ship to a page, it reports the page's build automatically: the Vite plugin stamps <html data-build-sha="…"> at build time from git rev-parse HEAD, and the widget posts that SHA once per page load — but only when a signed-in user is present, since the report is an authenticated call, and it is fire-and-forget: a failure is never shown to a visitor.

The beacon has a hard limit the CLI path does not: a browser cannot compute ancestry, so the widget can only match an exact commit. A comment is marked live by the beacon only when the page's build SHA equals the comment's commit SHA — not when the commit is merely contained in the build. That is why the beacon is the secondary path and status --deployed is the primary one.

Reporting the same build twice is safe

Write-once deploy timestamps

A comment's deploy date is written once, by the first build that carried the fix — a later build never moves it, so “when did this go live?” keeps answering with the deploy that actually shipped it, not the most recent one. Re-running status --deployed on a build you already reported is a no-op: the build is not duplicated, already-deployed comments are skipped, and the server answers firstSeen: false with an empty list of ids. A deploy step that runs on every retry of a job costs nothing.

The HTTP endpoint, for scripting

The CLI wraps a single call. Self-hosters and other tooling can report a build directly:

POST /api/projects/<key>/builds
Content-Type: application/json

{ "sha": "<deployed sha>",
  "containsCommitShas": ["<commit>", "…"] }