Skip to content

Latest commit

 

History

History
1883 lines (1649 loc) · 134 KB

File metadata and controls

1883 lines (1649 loc) · 134 KB

CLI Reference

This reference covers the public pointbreak command surface provided by the pointbreak crate.

Raw shore.* strings shown in schema examples are frozen persisted protocol identifiers, not a current command, environment family, or storage namespace.

Command output JSON is the machine-integration surface, under a tiered stability promise. A narrow hard core is frozen within each document's version:

  • the envelope discriminators (schema, version) on every document;
  • the field-paths a non-human consumer actually reads — pointbreak capture's changeId, revision.{revisionId,objectArtifactContentHash}, and reviewCursor.token, pointbreak input-request list's inputRequests[].{id,title,mode,reasonCode,trackId}, and pointbreak input-request respond's inputRequestResponseId and eventId;
  • the wire-value vocabularies — the assessment values, the input-request response outcomes, and the input-request mode (operative/advisory) and reasonCode value sets that ride the consumed input-request list field-paths (see the assessment and input-request sections). These vocabularies grow additively within a version: a new value may be appended (a soft-shell consumer selects the values it knows and tolerates the rest), but removing or renaming an existing value is a coordinated break (ADR-0029, Decision 7 amendment 2026-07-09).

Removing or renaming a hard-core field-path or value is a coordinated break: bump that document's version and migrate consumers. Everything else in the documents is soft shell — stable but additive-evolvable within a version: fields may be added, consumers must select by field name and tolerate unknown fields, and removing, renaming, or reshaping an existing field bumps the version. One documented exception is a command with multiple authority lanes: it may expose mutually exclusive soft-shell identity fields within one version when the command documents every alternative and the selected identity is unambiguous by field presence. Consumers of such a command must accept the documented identity union rather than requiring one lane's field. eventSetHash (authoritative journal reads) and projectionStamp (derived reads) are that pair on the history, attention, bounded revision-list, and review summary documents. Raw event files, artifact paths, and event filenames are internal storage details unless a command explicitly returns them.

Document-emitting commands accept --format <fmt>, where <fmt> is json, json-pretty, or text. Compact json is the default and the machine contract; json-pretty is the same document indented for manual inspection; text is a disposable human rendering that scripts should not parse.

Write acknowledgements

Capture, association writes (including association land), observation/assessment/validation adds, input-request open/respond, endorsement, fact port, artifact removal, and store link/migrate results include an acknowledgement. The Rust ingest result uses the same type. Existing store-profile, proof, and command-admission checks still apply.

A successful write confirms its durable authoritative outcomes. It does not promise that derived views are current. The four independent fields describe only this invocation:

Field Meaning
authorityOutcome created when all attempted authoritative components were new; existing when all were already present; mixed when both occurred; unchanged when none were attempted. Existing IDs, booleans, and counts remain the detailed result.
derived.availability off when the event writer had no derived coordinator; current when that write's catch-up succeeded; catching_up when its truth is durable but catch-up was deferred; unavailable when no usable derived observation could be returned; not_observed when no event write occurred.
legacyProjectionState Always not_attempted. The legacy state.json projection is retired; no write creates, refreshes or reads it. refreshed and refresh_failed remain decodable for receipts produced by earlier versions.
operationReceipt { "state": "not_recorded" } unless the invocation created or reused an existing durable operation binding. A response is not itself a durable operation receipt.

current and catching_up include derived.token with generationId, epoch, and headSequence; the other states omit it. This is a coordinate obtained from the event write, not a promise about a later read. Compare head sequences only within the same generation and epoch. A composite result retains the highest compatible head sequence; incompatible generations or epochs yield unavailable and a diagnostic. For multiple writes, unavailable dominates catching-up, then current, then off. An empty import/fold reports unchanged authority, not-observed derived state, and no recorded operation receipt.

Change capture names its existing durable recovery binding using operationReceipt.receiptId, equal to its operationId: state recorded means this invocation created that binding, and existing means it reused it. Reuse does not imply the requested Change operation had already completed; complete remains the completion detail. Other acknowledgement-bearing surfaces report not_recorded and omit receiptId. These fields create no new durable carrier and authorize no later action.

Call-specific diagnostics appear once in the existing top-level diagnostics array, never inside acknowledgement. Multi-event derived diagnostics retain the first occurrence of each code. Store link/migrate append their existing warnings after workflow diagnostics.

Write results report diagnostics about this invocation only (derived write state, skipped auto-record, ingest warnings). A write does not replay the event history after recording, so it does not report duplicates that already existed in the store. Store-wide hygiene diagnostics such as duplicate_semantic_* are reported by read commands (history, observation list, input-request list, validation list, assessment show) and the Inspector.

A writer reports derived-generation admission failure on its first attempted publication, not when its handle is constructed. For example, writing without a usable derived generation can succeed durably with derived.availability: unavailable and the top-level diagnostic derived_access_generation_unavailable.

These are additive v1 JSON fields: consumers must tolerate unknown fields. Strict decoders may need updating, and Rust callers constructing public result structs must supply the new fields. Existing text without diagnostics is unchanged. Text renderers that already consume result diagnostics may add advisory lines for derived catch-up or unavailability; land, fact port, link, and migrate keep their existing message/body text. The process-global stderr advisory channel remains unchanged, so a call-specific derived diagnostic can appear in both result text and stderr. Cross-channel suppression is not part of this contract.

Global Tracing Flags

Most commands accept optional tracing flags:

--log <filter>
--log-format <compact|pretty|json>
--log-file <path>

Tracing writes to stderr by default. When stdout is piped into JSON tools, prefer --log-file <path> so trace lines do not corrupt the JSON stream.

When --log-file <path> points inside the repository, Pointbreak treats that path as command-helper plumbing for the current command and excludes it from the reviewed snapshot and fingerprint.

pointbreak version

pointbreak version [--format <fmt>]

pointbreak version emits the pointbreak.version version 1 compatibility document. Its hard core is cliVersion, the semantic version of the running CLI; build, the build provenance described below; and documents, the frozen legacy schema-to-version compatibility map. Change-capable readers negotiate their larger coherent document set through pointbreak change profile or /api/v2/profile; those documents are deliberately not added to this legacy map. Inspector API payloads are versioned separately. Clients use the handshake that owns their reader cohort before decoding other command output.

build.source is git when the crate's manifest root contains checkout metadata (including a linked worktree .git file). In that mode, build.commit is the full lowercase commit ID, build.describe is the result of git describe --tags --always --dirty, and build.dirty reports tracked index or worktree changes at build time. Invalid or partial manifest-root Git metadata fails the build. When a source package has no manifest-root .git, build.source is package, build.commit is null, build.describe is package:<cliVersion>, and build.dirty is false. A package directory nested beneath some other checkout does not inherit that parent's Git identity.

JSON is authoritative for the full identity. A clean exact-tag binary has the exact tag in build.describe, its peeled full commit in build.commit, and build.dirty=false; semantic version alone does not establish release identity. Human pointbreak --version and pointbreak version --format text output append the concise build description in parentheses. Event producer versions remain semantic cliVersion; build provenance does not enter stored or signed event identity.

The documents map is sorted by schema. New entries are additive soft-shell growth, so consumers must select the schemas they require and tolerate additional entries. --format text prints a short human digest; compact JSON remains the default machine contract. The separate pointbreak --version flag prints the same semantic version and concise build description.

Actor Identity and Delegation

Every write records a writer actorId. By default it derives from the local Git identity (actor:git-email:<email>, then actor:git-name:<name>, then actor:local). Set POINTBREAK_ACTOR_ID to write under an explicit identity — agents use actor:agent:<agent-name>:

export POINTBREAK_ACTOR_ID="actor:agent:claude-code"

POINTBREAK_ACTOR_ID outranks the Git identity on every CLI write path, including paths without a per-call override; a malformed value is ignored and falls through rather than corrupting provenance.

Review read commands (history, the observation / input-request / assessment / validation list and show commands, revision show, and the inspector) discover a checked-in delegation map at <repo>/.pointbreak/delegates.json and resolve the human principal an agent wrote on behalf of, rendering it beside the writer as claude-code (for kevin@swiber.dev). Discovery is presence-based — absent file, no change. A malformed .pointbreak/delegates.json prints a single warning to stderr and the read proceeds with no resolution (advisory, never blocking). The file format is documented in storage-model.md.

The command group also previews the resolved writer and owns the write side of this config — creating a delegation record or describing an actor's kind/roles. See pointbreak identity whoami, delegate, and attest below.

Signing

Every write may carry an Ed25519 signature. Which key signs (if any) follows this precedence:

  1. --sign-key <name|path> on the write subcommand (a keystore key name or a path to a key file)
  2. POINTBREAK_SIGNING_KEY (same shape: a key name or a path)
  3. agent-context auto-keygen — under an actor:agent:* id, a passphrase-less per-machine key is generated on first write (see agent-authoring.md)
  4. the user-default keystore key named default
  5. none — the write proceeds unsigned

POINTBREAK_SIGNING=off (case-insensitive) disables signing entirely; POINTBREAK_SIGNING=auto (the default) resolves a signer where possible. POINTBREAK_HOME overrides the user-level key home (mainly for tests/CI). Signing never gates a write (with one exception, below): any resolution failure (no key, an unreadable key home, an unsupported algorithm, a malformed configured key, POINTBREAK_SIGNING=off) degrades to an unsigned write at exit 0 with a one-line advisory diagnostic on stderr — it never blocks. The sole exception is pointbreak endorse (below), where unsigned is a hard error because the signature is the endorsement's content. See signing-ux.md for the human / agent / CI flows and the unsigned → untrusted_key → valid ladder.

Review Lanes

Every recorded fact — an observation, an assessment, a validation check, an input request, a commit or ref association — is scoped to a review lane: a caller-chosen free-text label naming who or what is doing the reviewing, such as agent:codex or a human reviewer's own identity. There is no fixed vocabulary or required shape; the label is opaque to Pointbreak and exists so a revision's facts can be filtered and grouped by who recorded them.

  • On every write command that records a fact (pointbreak observation add, pointbreak assessment add, pointbreak validation add, pointbreak association record / land / withdraw, pointbreak fact port, pointbreak input-request open), --track <track-id> is required and stamps the lane that owns the new fact.
  • On read/list commands (pointbreak observation list, pointbreak input-request list, pointbreak validation list, pointbreak assessment show, pointbreak history, pointbreak revision show), --track <track-id> is optional and narrows the results to one lane; omitted, all lanes are returned.

pointbreak diff

pointbreak diff [--repo <path>] [--revision <id>] [--stat] [--color <auto|always|never>] [--theme <theme>]

pointbreak diff prints a captured revision's diff — base to target, from the frozen captured snapshot — as a text unified diff on stdout. It is the terminal reader for the immutable diff a revision recorded; its subject is always the captured snapshot, never the live working tree (git diff owns the live tree).

  • --repo <path> defaults to . and may point at the repository root or a subdirectory inside it.
  • --revision <id> selects the captured revision (a head seed): a current head resolves exactly, a superseded revision resolves its thread's current head. Omit it to diff the current capture; it is required when the store holds more than one candidate.
  • --stat prints only the diffstat (a per-file summary and totals), not the diff body.
  • --color <auto|always|never> controls ANSI syntax coloring of the diff body. auto (the default) colorizes only when stdout is a TTY, honoring NO_COLOR and CLICOLOR_FORCE (precedence: --color

    NO_COLOR > CLICOLOR_FORCE > isatty); piped or redirected output stays plain. Color is pure presentation — stripping the ANSI reproduces the plain diff exactly.

  • --theme <theme> picks the themed palette: auto (the default) detects the terminal background — light or dark — and selects the matching built-in palette; light / dark force a built-in; any other value names a bundled syntax theme, matched case-insensitively (bat's vocabulary, e.g. "Monokai Extended", "onehalflight", "nord"). Environment fallbacks: POINTBREAK_THEME, then bat's BAT_THEME (precedence: --theme > POINTBREAK_THEME > BAT_THEME > detection > dark). An unknown name from --theme/POINTBREAK_THEME is an error listing the valid vocabulary; an unknown inherited BAT_THEME warns on stderr and falls back. The terminal is queried only when colors are on, stdout is a direct truecolor or 256-color TTY, and the preference is auto — piped output never probes and stays deterministic. Themes apply on truecolor terminals (COLORTERM=truecolor or 24bit) and, downsampled to the nearest xterm-256 color, on 256-color terminals (TERM=*-256color, when COLORTERM does not advertise truecolor). Palette-index themes such as ansi and base16 keep their terminal palette indices on both lanes. Otherwise the 16-color palette follows the terminal's own theme. Intraline (changed sub-word) emphasis renders as an add/del background tint on truecolor and 256-color terminals (hand-picked 256-color tints per light and dark mode, as delta uses) and as an underline on 16-color terminals.
  • pointbreak diff is a filter, not a pager: it writes plain git-diff to any pipe or redirect and colorizes only when writing directly to a terminal, so it composes with the tools you already use — pointbreak diff | less -R to page, pointbreak diff | delta (or another diff renderer) to reformat, pointbreak diff > change.diff to save. There is no built-in pager and no --no-pager flag; use --color always to force color through a pipe (e.g. pointbreak diff --color always | less -R). A reader that closes the pipe early (pointbreak diff | head) is a clean exit.
  • The command is text-only and non-interactive: it has no --format selector and emits no JSON (machine consumers read the review documents, e.g. pointbreak revision show --format json). Its output is disposable — wording, layout, and ordering may change between releases, so nothing should parse it.
  • File headers carry the captured mode for /dev/null-sided changes: an added file with a recorded mode gets a new file mode <mode> line and a deleted file a deleted file mode <mode> line, next to the existing old mode/new mode pair for mode changes. This lets a saved change.diff read as a genuine add/delete instead of a /dev/null repository path, so ordinary textual changes replay with git apply. It is a fidelity improvement, not a guaranteed patch-export format: binary payloads, missing-final-newline markers, unusual path quoting, submodules, and object-ID index lines are out of scope, so treat pointbreak diff as human-oriented captured-diff readback.
  • When a revision's captured content has been removed from the store, pointbreak diff prints a short "content is unavailable" line (with the removed content's short id) instead of a diff body.

pointbreak change

pointbreak change profile [--repo <path>] [--format <fmt>]
pointbreak change list [--order activity_desc|change_id_asc] [--repo <path>] [--format <fmt>]
pointbreak change attention [--order attention_wait|activity_desc|change_id_asc]
  [--repo <path>] [--format <fmt>]
pointbreak change show <change-id> [--repo <path>] [--format <fmt>]
pointbreak change select <change-id> [--revision <revision-id>] [--allow-historical]
  [--cursor <token>] [--source captured|worktree|commit:<rev>]
  [--repo <path>] [--format <fmt>]
pointbreak change revision <change-id> <revision-id> --artifact-hash <sha256>
  [--include-body] [--repo <path>] [--format <fmt>]
pointbreak change resource <change-id> <revision-id> --artifact-hash <sha256>
  [--include-body] [--repo <path>] [--format <fmt>]
pointbreak change interdiff <change-id> <from-revision-id> <to-revision-id>
  --from-artifact-hash <sha256> --to-artifact-hash <sha256>
  [--repo <path>] [--format <fmt>]
pointbreak change create --operation-id <id>
  (--nonce <64-hex> | --root-revision <revision-id>) [--repo <path>] [--sign-key <name|path>]
pointbreak change join <change-id> <revision-id> --operation-id <id>
  [--repo <path>] [--sign-key <name|path>]
pointbreak change withdraw-membership <claim-id> --operation-id <id>
  [--repo <path>] [--sign-key <name|path>]
pointbreak change assert-relation <change-id> <successor-id> <predecessor-id>
  --successor-artifact-hash <sha256> --predecessor-artifact-hash <sha256>
  --operation-id <id> [--repo <path>] [--sign-key <name|path>]
pointbreak change withdraw-relation <claim-id> --operation-id <id>
  [--repo <path>] [--sign-key <name|path>]
pointbreak change link <first-change-id> <second-change-id>
  --relation same-work|related-work --operation-id <id>
  [--repo <path>] [--sign-key <name|path>]
pointbreak change capture --operation-id <id>
  (--initial-nonce <64-hex> | --cursor <token> --advance replace|parallel)
  [--predecessor <revision-id> --predecessor-artifact-hash <sha256>]...
  [--sign-key <name|path>] [capture options]
pointbreak change migrate-dry-run [--root <path>]... [--owner-decisions <file>]
  [--repo <path>] [--format <fmt>]
pointbreak change migrate --dry-run <file> --ack-manifest <sha256>
  --ack-cohort-manifest <sha256> --ack-minimum-reader review_change_revision_v1
  --ack-v0-9-unsupported --backup <external-dir> --operation-id <id>
  [--owner-decisions <file>] [--repo <path>] [--sign-key <name|path>] [--format <fmt>]
pointbreak change migrate-restore --backup <external-dir> --target-repo <path>
  [--format <fmt>]

change list and change attention emit their Changes in one server-owned presentation order and name it in the document's order member. change list defaults to activity_desc (newest contributing event first, ties on Change id ascending); change attention defaults to attention_wait (primary attention tier first, then the longest-waiting unresolved item, ties on Change id). change_id_asc remains available on both, and attention_wait is accepted only on change attention. The Inspector Changes and Attention pages use the same values and defaults, so the two front ends never present a different order for the same store. Each summary carries its activityAt instant and, when the Change has an anchored attention item, its attentionWaitAt key.

change attention lists Changes by lifecycle, not by item. It does not show advisory asks, or failed checks on a Change that is already accepted; those are items in pointbreak attention list. Read both to answer "what is outstanding?".

The Change reader begins with a complete capability profile. An untouched legacy root reports migration_required; a root with an admitted but incomplete transition reports migration_in_progress. In either state, semantic Change commands emit only the matching typed status document. A ready root names the durable minimum reader profile review_change_revision_v1 and advertises the exact document registry that must be accepted as one cohort before any Change payload is decoded.

The profile is a durable reader-capability contract, not a label unique to this migration. It records the minimum reader and coherent registry a root actually requires, so a later breaking cohort can require a successor profile without pretending an older client understands it. Relative to that required target cohort, migration_required, migration_in_progress, and ready describe root authority; reader_upgrade_required describes the separate case where a ready root requires a profile the requesting reader does not support. A partial, conflicting, or otherwise ambiguous authority record remains unavailable rather than being promoted to ready. The current bulk-adoption commands are one temporary procedure for the first cohort, not an implicit general-purpose migration path.

list, attention, and show render the authoritative Change projection. A Change may have multiple legitimate current Revisions; select therefore requires --revision when there is no unique current candidate and returns a self-hashed cursor rather than writing state. Supplying a previous --cursor revalidates the graph before returning a new selection. revision and resource require the exact Revision id plus its captured object-artifact hash; no current or successor Revision is substituted. Association comparisons and Revision interdiffs have their own typed identities and availability. The first reader cohort reports native Revision interdiff material as unavailable instead of substituting a live Git diff.

The write commands are available only when the store profile is ready; an untouched legacy root fails with migration_required, and an admitted but incomplete transition fails with migration_in_progress, before proposal or retry state is written. Every Change mutation takes a stable --operation-id. Retrying the same operation with the same inputs is idempotent; reusing the id with different inputs is refused. create, join, and the membership/relation/link commands expose the low-level append-only claim vocabulary. change capture is the higher-level workflow for initial, replacement, parallel, and multi-predecessor consolidation captures. Its --summary <text> is the label shown on Inspector Change cards; when it is omitted, the command prints the same one-line stderr notice as pointbreak capture and the receipt carries revision.summary: null. Every Change mutation participates in the same optional signing-key resolution as the review-writing commands.

migrate-dry-run is read-only. It inventories one or more legacy roots, reports anomalies and retained manifest overlaps, and accepts an explicit owner-decision manifest for deterministic replanning. It does not activate a store. migrate is the only activation route. It accepts the exact approved dry-run and both of its acknowledged hashes, requires the new minimum-reader and v0.9 incompatibility acknowledgements, and creates a byte-verified L0 backup plus a fully signed resume plan in the supplied external directory before publishing activation. The same command and operation id resume an interrupted M1 transition without re-signing or recomputing the legacy graph. Completion is appended last; ordinary Change reads and writes remain unavailable until that L2 record verifies. A repeated completed invocation returns existing. migrate-restore verifies that retained backup again and copies it only into an empty store with a different placement identity. The result is a separate L0 recovery fork that requires its own fresh dry run; it never rolls an M1/L2 store backward in place.

The signed v0.9 reader remains compatible only with untouched legacy roots. It is not a reader for a root once the Change/Revision capability transition begins or completes.

pointbreak inspect

pointbreak inspect [--repo <path>] [--host <loopback-ip>] [--port <n>] [--open] \
  [--api-only] [--format <text|json>]

pointbreak inspect starts a small local web server that visualizes the worktree's resolved store for tracing event timelines and outcomes — the kind of inspection that is awkward against the raw JSON files or per-command output.

  • --repo <path> defaults to . and may point at the repository root or a subdirectory inside it.
  • --host <loopback-ip> defaults to 127.0.0.1. Non-loopback binds are rejected before the server attempts to listen. --port <n> defaults to 7878; use --port 0 to bind an ephemeral port, which is then printed.
  • --api-only omits the static browser shell and assets. --open launches the browser shell and is rejected only with --api-only.
  • --format text|json controls startup output independently of the served surface. Text output is the default: the browser surface prints a fragment capability URL, while --api-only prints labeled endpoint and token fields. JSON output is exactly one compact pointbreak.inspect-startup v1 line with the actual loopback host/port and process-local bearer.
  • Every process generates a distinct bearer. All requests require the exact advertised Host, and every /api/* request also requires exactly one Authorization: Bearer <token> before routing, store, projection, or cache work. Authentication failures return an empty 401. The fixed static shell and assets need no bearer and never touch the store; they are the recovery surface when a browser lacks or loses its credential.
  • The browser moves the fragment token into origin-scoped sessionStorage and scrubs it before routing. Its connection chrome distinguishes authentication failure, an unreachable server, and an authenticated protocol/data error, with route-preserving Reconnect and Retry actions. The bearer must not be logged, placed in a request target or referrer, or persisted outside the documented startup/session credential carriers.
  • The server runs until interrupted with Ctrl-C.

The bundled page negotiates /api/v2/profile before any semantic fetch or paint. On a ready root its default Timeline renders the typed event stream with free-text, event-type, track, Change, and exact Revision filters; oldest/newest ordering; signed previous/next pages; event details; keyboard navigation; and explicit follow/park behavior for incoming events. The server owns the filtered chronology and Change-aware attribution. The browser keeps only a bounded page-local window in the DOM and never infers one Change or Revision when an event has multiple contexts.

Follow and park are Timeline actions. While an event detail is open, the Timeline follow control stays visible and reports the retained monitor state (Following, Parked, or Show N new), but it is not operable: the toggle is aria-disabled there and acts only on the Timeline route. The detail pane reads the loaded history page and never a parked window, so the monitor observes incoming events only on the Timeline itself; the count shown with a detail open is the one from the last Timeline observation, not a live count. Keeping park and resume on the Timeline keeps follow semantics defined in one place instead of adding an interaction between the monitor and exact-event reading. Return to the Timeline to park or resume.

The Changes and Attention lenses render Change cards, explicit current-Revision choices, relation-claim provenance, exact captured resources, fact origin/currency, association comparisons, and separately identified Revision interdiffs. Parallel current Revisions remain distinct from a divergent replacement graph; choosing a Revision never turns either topology into acceptance. Validation evidence and reader-relative signature status remain advisory presentation, never a gate or verdict. On a legacy or in-progress root the page renders only the typed migration state.

The inspector is a read-only, single-store, localhost developer tool. It reads through the same validated projections as pointbreak history and pointbreak revision show rather than parsing raw storage, and it serves over a synchronous, dependency-free HTTP server with no async runtime. The Most of the small JSON API remains an internal surface for the bundled page. The Change cohort begins at /api/v2/profile; /api/v2/changes, /api/v2/attention, and exact Change/Revision member routes are accepted only against that profile's complete registry and coherent projection stamp. Once a root is ready, legacy aggregate routes return a typed 426 Upgrade Required before any partial legacy payload. On legacy roots those aggregate routes remain readable by the signed v0.9 binary; the capable bundled page does not fall back to them and paints only migration_required. Store activation is a separate explicit operator transition. Once a transition enters the in-progress state, legacy aggregate routes return a typed 409 Conflict migration document.

Both surfaces decide legacy admission from one table. The difference between them is intentional: the ordinary command fence keeps every non-Change command away from a pre-migration store, while the Inspector keeps migration-era readers working on untouched legacy roots.

Store state Ordinary CLI commands (history, revision list, attention list, review writers) Inspector legacy aggregate routes (/api/history, /api/revisions, /api/threads, /api/attention, /api/freshness, member reads)
Untouched legacy root (no activation record) refused with migration_required served, for the signed v0.9 reader
Activation root present, migration still required refused with migration_required 409 Conflict, pointbreak.store-migration-required
Migration in progress refused with migration_in_progress 409 Conflict, pointbreak.store-migration-in-progress
Ready Change-aware root served 426 Upgrade Required, reader_upgrade_required

The change family, the store placement commands, key, identity, inspect and version answer their own typed capability documents instead of taking this table. While the derived view cannot serve, the Change-first entry routes (/api/v2/profile, /api/v2/changes, /api/v2/history, /api/v2/attention) accept the same explicit access=authoritative election the legacy routes accept; the derived-access section below describes it.

Three v1 bundled-pair documents are compatibility-advertised by pointbreak version: /api/snapshots/{id} returns pointbreak.review-snapshot, /api/freshness returns pointbreak.inspect-freshness, and JSON startup emits pointbreak.inspect-startup. /api/version mirrors the exact pointbreak.version v1 document emitted by pointbreak version. The self-described pointbreak.inspect-event-history document and the remaining Inspector-private payloads are not promoted contracts.

The legacy v0.9 Inspector-private /api/revisions collection remains only for migration-era readers on legacy roots. It is snapshot-bound and paged, but it is not a lens in the current bundled page; ready Change-aware roots refuse the legacy aggregate cohort as described above. The current Changes and Attention lenses page /api/v2/changes and /api/v2/attention. They open an exact contextual member through /api/v2/changes/{changeId}/revisions/{revisionId}?artifactHash={objectArtifactContentHash}, so a Revision selection always carries its Change membership and exact captured-content identity. Each page's presentations[].currentRevisions[] entries carry summarySource; a supplied proposal summary also carries revisionProposalSummary and the finished label, while an absent one carries no label and the server-owned absentSummaryCue ("No summary supplied"). The card then keeps the exact Revision id as its headline and shows the cue as a muted state line. Both members are additive, so the page version stays 1. Each capture remains distinct, including shared-commit siblings; the CLI's default revision list presentation may still fold those siblings into a grouped row.

Every worktree of a clone resolves the shared common-dir store (<git-common-dir>/pointbreak), so the inspector renders snapshots captured in sibling worktrees as well as the current one. The /api/snapshots/{id} payload is content-only: it carries the immutable diff content and its contentHash only — no revisionId, source, base, or target. The captured worktree path is therefore simply absent from the snapshot wire (there is nothing to redact). Endpoint/target display lives on /api/revisions/{id} and /api/revisions, derived from the revision projection (a path-private targetDisplay block), not from the snapshot artifact. pointbreak revision list JSON still carries target.worktreeRoot unchanged for Git-backed worktree captures. A provenance-free revision omits the complete source / base / target triple and receives targetDisplay.kind: "non_git" with a non-Git label.

pointbreak capture

pointbreak capture [--repo <path>] [--base <rev> | --root | --staged | --unstaged] \
  [--target <rev>] [--include-untracked] [--allow-empty] \
  [--summary <text>] [--path <pathspec>]... [--operation-id <id>] \
  [--review-cursor <token> --advance replace|parallel] \
  [--also-supersedes <revision-id>@<object-artifact-sha256>]...

pointbreak capture records a new exact Revision in a stable Change: the base endpoint, target endpoint, and captured diff snapshot. Without --review-cursor, it creates a new independent Change. With --review-cursor --advance, it revalidates that exact Change/Revision selection and records a replacement or parallel Revision. Repeated --also-supersedes REVISION@ARTIFACT_HASH arguments add exact current predecessors for a consolidation. The legacy proposal-borne --supersedes spelling is rejected with an actionable error.

--operation-id supplies the durable retry identity; when omitted, Pointbreak generates one and returns it in the receipt. The JSON receipt is pointbreak.change-capture-receipt.v1 and includes changeId, revision.{revisionId,objectArtifactContentHash}, reviewCursor.token, per-event outcomes, and whether the operation is complete. Retrying the retained operation never silently adopts a different source snapshot.

By default capture reads the local Git worktree from HEAD (or Git's empty tree before the first commit) to the working tree (source git_worktree). That default is a combined "what differs from the baseline" capture: it includes staged and unstaged tracked changes because both differ from HEAD. Like git diff HEAD, default capture excludes untracked files; add --include-untracked to synthesize untracked files as added files in the captured snapshot. In a newly initialized repository with no commits, default worktree capture uses Git's empty tree as the base endpoint and the working tree as the target. If the only files are still untracked, use pointbreak capture --include-untracked.

By default, a selected source that produces zero changed files is an error. The error suggests likely source flags such as --include-untracked, --staged, or --unstaged when they might explain the empty result. Use --allow-empty to intentionally record an empty revision.

--summary <text> attaches an optional human-readable discovery label to the immutable capture event. It is the label shown on Inspector Change cards, and it is projected into revision list, history, the Inspector, and the VS Code extension so people and agents can select the intended revision without interpreting opaque IDs. The summary is descriptive metadata and does not affect revision or object identity. An omitted summary stays absent from the event and read documents for backward compatibility. The capture still succeeds without one, but it prints a one-line stderr notice (notice: no --summary supplied; Inspector cards and receipts will show only the exact Revision id), the JSON receipt carries revision.summary: null explicitly, and the text receipt reads summary: none supplied. change capture behaves the same way. Because the capture event is immutable, rerunning the same content with a different summary is a conflicting proposal rather than an edit; choose the label on the initial capture.

  • With --base <rev>, capture instead records the committed range from <rev> to --target (default HEAD) as a git_commit_range source. Both revs are resolved with git rev-parse to commit OIDs at capture time: annotated tags peel to their commit, and a rev that does not exist or does not name a commit (a blob or tree) is rejected with an error that names the rev. The snapshot is the base..target tree diff with no working-tree, index, or untracked involvement, so both endpoints serialize as git_commit and no worktree path appears in the output. --target defaults to HEAD under --base. Re-capturing the same range is idempotent and reports eventsExisting, and an equivalent rev spelling (HEAD~1 versus the resolved OID) captures the same revision because rev spellings are never stored (and the same summary, when supplied, keeps the proposal byte-identical). Like worktree capture, a range capture lands in the shared common-dir store, so it is immediately visible from sibling worktrees (see below).
  • With --root, capture records Git's empty tree to --target (default HEAD) as a git_root_commit source. The base endpoint serializes as git_tree; the target endpoint serializes as git_commit. This is the supported way to review a repository's first commit, or any explicit target commit as "all files added", without creating orphan-branch workarounds. --root cannot be combined with --base, --staged, or --unstaged, and --target is accepted only with --base or --root. Like --base, root capture reads only committed trees: the working tree, index, untracked files, and command-helper paths do not affect the captured revision.
  • With --staged, capture records staged changes only as a git_staged source. If HEAD exists, the base endpoint is the current commit and the target endpoint is the captured Git index tree. If the repository has no commits yet, the base endpoint is Git's empty tree and the target is still the captured index tree. The working tree and untracked files are not read, so unstaged edits do not affect the captured revision.
  • With --unstaged, capture records the captured index tree to the working tree as a git_unstaged source. This mirrors git diff from the index by default: staged changes are in the base endpoint and untracked files are excluded. Add --include-untracked to synthesize untracked files as added files without staging or mutating them. In a repository with no commits, --unstaged --include-untracked captures untracked working-tree files from the empty index tree to the working tree.
  • --include-untracked is valid only with default worktree capture or --unstaged. It is rejected with --base, --root, and --staged because those modes are tree/index captures rather than worktree-plus-untracked captures. To capture a new repository's untracked initial files, use pointbreak capture --include-untracked, not pointbreak capture --root --include-untracked.
  • --allow-empty is valid with every capture source. Without it, Pointbreak refuses to record a revision whose selected source has no changed files. This keeps accidental empty captures from hiding a missed --include-untracked, --staged, --unstaged, or pathspec typo while still allowing an explicit empty revision when that is the intended review object.
  • Durable state lands in the shared common-dir store at <git-common-dir>/pointbreak under the clone's Git common directory (the default for every worktree). An ephemeral worktree instead keeps its own discardable .pointbreak/data/ store. A legacy flat .pointbreak/ store from before the .pointbreak/data/ layout is a retired pre-1.0 format: it is detected and refused, not migrated — distinct from pointbreak store migrate, which folds a pre-flip worktree-local .pointbreak/data/ store into the shared store; see storage-model.md.
  • Opting into ephemeral mode generates a committed .pointbreak/.gitignore (two lines: data/ + *.local.json) when the paths are not already ignored, so the worktree-local store stays out of git status; the file is visible, meant to be committed, and survives clone. Writer-initializing commands against the ephemeral store generate it too; a shared-store write generates nothing (the shared store lives inside .git/, which git already ignores) and never mutates the working tree. Nothing writes .git/info/exclude anymore, and no tracked .gitignore is ever modified. Committed config siblings (.pointbreak/delegates.json, .pointbreak/actor-attributes.json, .pointbreak/allowed-signers.json, .pointbreak/store.json) stay tracked; only .pointbreak/data/ and the private .pointbreak/delegates.local.json, .pointbreak/actor-attributes.local.json, and .pointbreak/store.local.json overrides are excluded.
  • The store subtree (events/ and artifacts/) is the same wherever it resolves: the shared common-dir store at <git-common-dir>/pointbreak by default, or an ephemeral worktree's own .pointbreak/data/.
  • events/ stores immutable event files.
  • No state.json projection is written. A leftover file from an earlier version is inert and may be deleted.
  • Full captured snapshots are Pointbreak-owned immutable object artifacts under artifacts/objects/.
  • The work_object_proposed event binds to the object artifact's canonical content hash; the content-only artifact body carries no revision identity or endpoints (those live on the event).
  • Output is compact pointbreak.change-capture-receipt.v1 JSON and includes the Change, exact Revision and object-artifact hash, a fresh review cursor, the retry operation, and write outcomes.
  • With --path <pathspec> (repeatable), the capture is scoped to the given git pathspec(s): both the tracked diff and any enabled untracked-file synthesis include only matching files. This composes with the default worktree capture, with --base/--target, with --root/--target, and with --staged or --unstaged. The syntax is native git pathspec — including magic such as :(exclude)... — executed by git itself, and pathspecs are interpreted relative to the repository root regardless of the invoking directory. The recorded set is order-independent (sorted, deduped, trailing slashes normalized on plain paths) and is part of the captured revision's identity: the same range captured under a different scope is a different revision, while identical captured content still shares one content object. A scope that matches no changed files is an error unless --allow-empty is passed; with --allow-empty, the empty revision still records the requested scope. The scope is visible in pointbreak revision show, pointbreak revision list, and pointbreak history under source.pathspecs; an unscoped capture carries no pathspecs key and its identity is unchanged from before the option existed. (This is deliberately git pathspec syntax, not the gitignore-style globs of .pointbreak/sensitivity.json — capture scoping is executed by git, while the sensitivity exclude config is matched by Pointbreak at scan time.)
  • git_tree, git_index, and git_working_tree are endpoint states in the recorded model. The source selector decides which endpoint pair is captured: default worktree (HEAD or empty tree to working tree), committed range (commit to commit), root (empty tree to commit), staged (commit or empty tree to index), or unstaged (index to working tree).

V1 storage is local and synchronous. The shared common-dir store may take concurrent writes from multiple worktrees of the same clone, kept safe by content-addressed writes and a regenerable projection rather than a lock. V1 does not add a daemon, delivery queue, approval flow, async storage, remote storage, or note mutation.

By default every worktree of a clone resolves the shared common-dir store at <git-common-dir>/pointbreak, so pointbreak capture lands its capture directly there — no setup step — and the capture is immediately visible to revision list, revision show, and history from any sibling worktree. An ephemeral worktree instead captures into its own discardable .pointbreak/data/ store (see pointbreak store).

The native review write commands — pointbreak observation add, pointbreak input-request open and respond, pointbreak assessment add, and pointbreak validation add — behave the same way. They resolve the shared common-dir store, so you can record a fact against a revision (or related observation, assessment, or request) captured in a sibling worktree, and the fact lands directly in that shared store, visible to every worktree in place. An ephemeral worktree writes the fact to its own .pointbreak/data/ store, unchanged.

pointbreak store

pointbreak store status [--repo <path>] [--format <fmt>] [--show-paths]
pointbreak store derived status [--repo <path>] [--format <fmt>]
pointbreak store derived build [--repo <path>] [--format <fmt>]
pointbreak store derived rebuild [--repo <path>] [--format <fmt>]
pointbreak store paths [--repo <path>] [--format <fmt>]
pointbreak store mode (shared | ephemeral | show) [--repo <path>] [--format <fmt>]
pointbreak store migrate [--repo <path>] [--include-ephemeral] [--retire-source] [--format <fmt>]
pointbreak store link [<slug>] [--repo <path>] [--include-ephemeral] [--include-sensitive] [--retire-source] [--format <fmt>]
pointbreak store unlink [--repo <path>] [--format <fmt>]
pointbreak store forget <slug> [--yes] [--force] [--format <fmt>]
pointbreak store list [--format <fmt>]
pointbreak store remove [--repo <path>] (--snapshot <id> | --revision <id> | --ref <name> | --range <a>..<b> | --unreachable) [--sign-key <key>] [--format <fmt>]
pointbreak store gc [--repo <path>] [--format <fmt>]
pointbreak store compact [--repo <path>] [--format <fmt>]

Transition availability: store migrate and store link retain their command syntax and historical placement contracts, but their transfer writers are inactive in this build. Untouched and partially migrated roots fail at the capability fence; a Change-ready root reports change_store_transfer_unavailable. This is distinct from the explicit change migrate command, which activates one exact owner-approved legacy root in place after retaining a verified external backup. It does not move a store between placements. Do not copy a test capability fixture into an owner store.

pointbreak store commands inspect, configure, and maintain the review store the current Git worktree resolves. By default every worktree of a clone — the main worktree and every linked worktree alike — resolves the same shared common-dir store at <git-common-dir>/pointbreak (the path under the repo's Git common directory), automatically and with no setup step. Because linked worktrees share one Git common directory, a capture in any worktree is immediately visible from its siblings. By default this is a per-clone store, not a user-level multi-repository store or remote sync service; a clone can opt into the machine-wide user-level family store tier once exact Change store transfer is activated (see the retained placement contract below).

pointbreak store status resolves the store and emits pointbreak.store-status JSON.

pointbreak store derived status|build|rebuild operates on the disposable derived-access generation for the exact store selected by --repo. The event journal and content store remain authoritative: these commands do not replace, migrate, or mutate loose truth. When POINTBREAK_DERIVED_ACCESS is unset, the derived profile is active; set it explicitly to off for immediate rollback. The stable derived/ container and its locks, leases, quarantine, and retired artifacts live directly beneath the exact resolved authoritative store root. Clone-local, ephemeral, and user-level family stores therefore each keep their own matching disposable generation; Pointbreak does not maintain a second global derived-path registry.

  • status is strictly read-only. It reports the selected namespace and lifecycle availability without creating a directory, acquiring a rebuild lease, or starting background work. Its pointbreak.store-derived-status document is path-free. If both the stable derived/ namespace and its legacy predecessor are present, text output identifies both local paths so the operator can retain one disposable copy and move the other aside; Pointbreak never guesses, merges, or deletes either. When the cause of an unavailability is typed, the document adds a reason field. The only reason today is journal_unavailable: on Windows, the NTFS volume that holds the store has no active USN change journal. availability is then unavailable, nothing retries it, and detail reads, for a store on D::

    journal_unavailable: the NTFS change journal is not active on volume D: (os error 1179), so derived access cannot prove authority on it; an administrator can create one with `fsutil usn createjournal m=<size> a=<delta> D:`, or set POINTBREAK_DERIVED_ACCESS=off to use authoritative reads (slower but correct); Pointbreak never creates a journal
    

    A background run that stopped on it prefixes the same text with background recovery stopped: , and build and rebuild fail with it. See Windows: the NTFS change journal.

  • build synchronously creates or repairs a usable generation only when needed. If a validated current generation already exists, it emits a no-op pointbreak.store-derived-build receipt.

  • rebuild synchronously constructs and publishes a replacement generation even when the old generation remains readable. It emits a pointbreak.store-derived-rebuild receipt after publication.

If authoritative truth cannot be proven stable during a build or rebuild (for example, a busy NTFS volume exhausts the change-journal budget), the rebuild runs again, up to three attempts in total, before it fails.

Who may do what to the disposable derived generation is fixed by the actor's role:

Role Commands and routes May do Refuses
Observe store derived status; Inspector status Report availability, namespace and progress Never creates state, takes an exclusive lock, starts work or moves state aside; store derived status is refused on a store that still requires migration, while Inspector routes answer typed documents instead
Maintain Ordinary bounded reads; Inspector data requests Serve a validated current generation; after activation, ask the existing background maintenance to catch up Never replace a generation or move invalid state aside; report it and fall back
Recover store derived build; Inspector Retry Move invalid disposable state aside and build a usable generation Derived access set to off; a deferred or conflicting namespace transition; a store that still requires migration
Replace store derived rebuild; Inspector Retry; change migrate Publish a replacement while the old generation stays readable until completion The same refusals as recover

On an activated store, invalid disposable state stays in place until an explicit recover or replace action; ordinary reads keep reporting it and fall back to authoritative data.

When both the stable derived/ root and its legacy predecessor exist at once, derived access is unavailable, not off. Ordinary bounded CLI reads fall back to authoritative data with the one-per-process hint. Where admission permits them (the legacy aggregate routes on an untouched legacy root), Inspector data routes answer the typed unavailable document and serve only under the explicit access=authoritative election; the exact-read, search, freshness and bare poll-probe routes keep their existing behaviour. Change-first routes answer typed migration documents on pre-migration stores and the typed projection_invalid document on ready stores. Status names the conflict and text output prints both paths; build, rebuild and the Inspector Retry refuse or do nothing until an operator moves one root aside or selects explicit off. A conflict that appears while an Inspector is already running is reported through the lifecycle error until that process restarts.

Build and rebuild may scan the complete event history and can therefore be expensive on a large store. Progress is written to stderr; stdout contains exactly one completion document, so scripts can consume it without parsing progress. A cancellation or failure preserves authoritative loose truth and any previously valid generation. Set POINTBREAK_DERIVED_ACCESS=off to disable all derived reads and writes immediately; while it is set, build and rebuild refuse to run. This is also the rollback posture for an older binary that does not understand the stable derived/ namespace. If a live lease defers the namespace transition or both namespaces conflict, the command still emits its machine-readable receipt to stdout but exits non-zero; the requested build did not complete, so shell callers must not proceed as though a generation is usable.

A first bounded CLI read with no usable generation falls back to authoritative loose data and emits one actionable hint for the exact store and process; it does not synchronously rebuild history. A first write publishes authoritative loose truth once and reports derived degradation, leaving the disposable generation for a later build or rebuild. Inspector is the interactive exception: it starts one asynchronous first build while keeping the shell and explicit authoritative fallback available.

When the derived profile is active and current, output-bounded history pages, attention list, explicitly bounded revision list --limit pages, and summary show use it without enumerating the event directory. These commands keep their domain document schemas and expose projectionStamp instead of pretending that the bounded freshness identity is an eventSetHash. An absent or unusable generation falls back to the authoritative journal for that invocation and prints one store derived status|build hint. Unbounded, search, ref-filtered, audit, replay, transfer, repair, migration, removal, and compaction work remains authoritative.

The rollout and lifecycle are natively qualified on macOS/APFS and Windows/NTFS. Linux remains compile/CI qualified; that support surface does not substitute for retained-scale Linux measurements. Existing retained L100/C262 packages remain the scale authority, and first build or deliberate rebuild remains exceptional, history-proportional maintenance rather than an ordinary read or write path.

pointbreak store paths is the supported path-discovery seam. It emits pointbreak.store-paths version 1 with the selected tier and exact worktreeStore, commonStore, binding, home, and keys paths. The binding is <git-common-dir>/pointbreak.link.json; the common store is <git-common-dir>/pointbreak. Linked worktrees share both through their Git common directory. Use this command in scripts instead of reconstructing Pointbreak paths.

  • mode is local (the clone-local common-dir store), ephemeral (a worktree pinned to its discardable .pointbreak/data), or user-level (a clone linked to a family store). storeRef is local for the first two and the family slug for user-level. A user-level status additionally carries repositoryFamilyRef, cloneRef, liveCloneCount, orphaned, and lastWrite; the other two tiers omit them. These family fields sit outside the frozen hard core under this document's tiered stability promise.
  • storeIdentity and contextIdentity are opaque, machine-local identifiers for the resolved store and current worktree context. Consumers may compare them for equality but must not parse them. Nested paths in one worktree report the same pair; linked worktrees sharing a store have the same storeIdentity and different contextIdentity values.
  • inventory reports eventCount, eventBytes, artifactCount, artifactBytes, totalBytes, optional untrackedBytes, largestArtifacts, and revisionObjects. Artifact entries use opaque artifact refs rather than filesystem paths. Each revisionObjects entry carries a revisionIds list (sourced from the work_object_proposed events keyed by objectId plus objectArtifactContentHash), because one object artifact may be referenced by several revisions under the shared-store model (#146), while a rebased recapture can store another artifact for the same stable object id.
  • sensitivity reports policyOutcome plus redacted findings. Finding references use file:sha256:* refs, and the JSON document never prints secret values or source file paths. The local-only --show-paths flag is the one exception, and only on the text lane — see Sensitivity exclude globs.

Sensitivity findings are reported but do not currently abort a write. A hard-blocking policy and explicit override controls are a forward-looking note for when movement can target a wider store; blocking findings still name only safe finding kinds, such as known_token, and command output does not print the secret text or file path.

Every review read command resolves the shared common-dir store: revision list and revision show, history, the observation, input-request, and validation lists, the association list, and assessment show read it from any worktree of the clone, including hydrated bodies and the captured snapshot. Authoritative documents identify that store state with eventSetHash; eligible bounded reads served by a current derived generation carry projectionStamp instead. Both identities move when the visible journal state moves, but a projection stamp is not a full-set hash.

pointbreak store mode reads or sets a per-worktree store mode that controls where the worktree's review data lands. pointbreak store mode ephemeral pins the worktree to a discardable worktree-local .pointbreak/data store — the privacy escape hatch for sensitive or throwaway work whose bytes should disappear when the worktree is removed. pointbreak store mode shared (the default) uses the shared common-dir store. The mode is written to a committed .pointbreak/store.json, and may be overridden privately by a git-excluded .pointbreak/store.local.json (the local file wins, the delegates.json / delegates.local.json precedent). A malformed or unsupported config is a hard error rather than a silent fallback. pointbreak store mode show reports the resolved mode without changing it. All three forms emit pointbreak.store-mode JSON with mode (shared | ephemeral) and source (default | committed | local); the body embeds no storage path.

Sensitivity exclude globs

The worktree sensitivity scan (run by pointbreak store status and pointbreak store migrate's consent gate) supports a committed .pointbreak/sensitivity.json plus a git-excluded .pointbreak/sensitivity.local.json (covered by .pointbreak/.gitignore's *.local.json line) listing path globs the scan skips — the targeted alternative to the blanket --include-ephemeral override when a repo's own test fixtures carry scanner-triggering strings:

{
  "schema": "shore.sensitivity-config",
  "version": 1,
  "excludeGlobs": ["tests/**", "src/session/store/sensitivity.rs"]
}

The two files merge by union (committed order first, then novel local entries) — deliberately diverging from the local-replaces-committed rule store.json/delegates.json use, because this is a list: replace would force copying the whole committed list to add one local entry, union grants nothing replace couldn't, and the audit counts make any widening visible. Default is empty (scan everything; opt-in only).

Glob semantics are a documented gitignore-style subset matched against the repo-relative path: a leading / or any interior / makes the pattern rooted (tests/**, src/lib.rs); a slash-free pattern matches any path component at any depth (*.pem, data); a trailing / marks a directory pattern matching only paths inside it; ** spans segments (zero or more interior, one or more trailing); * and ? never cross /. Negation (!), empty patterns, and malformed or unsupported-version config are hard errors naming the offending file — the config gates a protection, so a misread never silently changes coverage.

An excluded path is not scanned — an explicit operator opt-out, kept honest by the audit surfaces: pointbreak store status reports sensitivity.excludedPathCount and sensitivity.excludeGlobs[{glob, matched}] (zero-count globs included; a dead glob is itself worth seeing), and pointbreak store migrate reports sensitivityExcludedPathCount whenever its gate scan ran (absent under --include-ephemeral, which skips the scan). Excluded paths themselves are never listed — the scan's redacted file:sha256:* posture stands. The gate behavior is unchanged: a block finding outside the excludes still refuses without --include-ephemeral.

Seeing which files matched (pointbreak store status --show-paths). A finding names only its kind and a redacted file:sha256:* reference, so on its own it does not tell you which file to exclude. --show-paths closes that loop: it re-runs the same scan (the same matchers, the same exclude globs) locally and lists the real matched worktree paths grouped by finding kind, so you can author a targeted excludeGlobs entry. The link/migrate sensitivity gate errors point at this command.

--show-paths is text-only: it forces the text lane and refuses an explicit --format json / --format json-pretty. That restriction is deliberately not a security barrier — the listing prints to your own terminal, the paths are your own local files, and plain text is as machine-readable as JSON, so nothing is being withheld from a program. It exists only to keep the versioned pointbreak.store-status JSON document a single, uniformly path-free shape, so a tool that pipes that document into a log, an index, or a relay never depends on a flag to stay path-free. The redaction that genuinely matters is on the stored and forwarded data — the events written to <git-common-dir>/pointbreak and the default pointbreak.store-status document, which can cross machine, family-store, and relay boundaries and would otherwise leak your local filesystem layout to whoever reads the store. --show-paths never writes to the store or emits JSON, so it sits outside that contract by construction: the type that carries the real paths is not serializable, and the paths reach nothing but stdout.

A pre-flip worktree-local .pointbreak/data store on a non-ephemeral worktree (data written before the shared common-dir default) is detected on any read or write. The retained transfer contract for pointbreak store migrate folds that legacy store into the shared common-dir store non-destructively by default: it copies events and artifacts forward and leaves .pointbreak/data in place, so you can verify the result and then remove .pointbreak/data yourself to finish the switch. It is idempotent (re-running reports the already-present facts as existing), and it refuses an ephemeral or sensitivity-flagged worktree unless you pass --include-ephemeral. That transfer is not executable in this build; the command fails closed as described above.

--retire-source completes the switch in one command: after the fold, an independent verification walks every durable file in the source store (events/ and artifacts/, recursively; only in-flight *.tmp files are excluded — a leftover store-root state.json sits outside those trees, and a nested file merely named state.json is verified like any other) and requires each to be present in the shared store — artifacts by content, events by content ignoring the import's own ingest-provenance stamp. Retirement then deletes exactly the files it verified, plus disposable rebuildable data, and never deletes recursively. It keeps .pointbreak/data and its authority lock file, so a leftover directory holding only authority.writer.lock is expected and the very next read resolves; sourceRetired is true when nothing else remains (see storage-model.md). On any missing or divergent file — including an orphan artifact no event references, which the fold deliberately does not carry — the command errors, names the offending paths, and deletes nothing. It refuses before folding, with an error whose message begins source_busy;, while another Pointbreak writer holds .pointbreak/data, and refuses — naming the entry and deleting nothing — when the store holds an entry retirement does not verify, such as operations/. A record that appears while retirement is checking is kept: nothing is deleted, sourceRetired is false, and a source_retirement_residue diagnostic asks for a rerun. A source with no durable files at all (only a leftover store-root state.json, derived-access data, or the empty directories the writer pre-creates) is retired as a husk without a fold, under the same rules; a source holding artifact files but no event files is refused outright. Classification is by file counts, never directory existence.

It emits pointbreak.store-migrate JSON with eventsCreated, eventsExisting, artifactsCreated, artifactsExisting, sourceEmpty, sourceRetired, verifiedEvents, and verifiedArtifacts. (This is distinct from the legacy flat .pointbreak/ layout, a retired pre-1.0 format that is detected and refused rather than migrated; see storage-model.md.)

The retained pointbreak store link [<slug>] contract promotes a clone into the opt-in user-level family store at <pointbreak-home-root>/stores/<slug>/, a per-machine store shared across independent clones of the same repository family so review facts survive removing any one clone. The binding is recorded per physical clone in the git common dir (pointbreak.link.json under .git/), so it never travels in a commit and a single pointbreak store link binds the main checkout and every current and future git worktree of that clone. The per-worktree .pointbreak/store.local.json file is mode-only: a familyRef or cloneRef there is rejected with guidance to run pointbreak store link <slug>. A worktree can still opt out locally with pointbreak store mode ephemeral. When a worktree writes to its clone-local store while a sibling worktree of the same clone is linked, pointbreak store status, every verb that resolves a write store (capture, change writers, association record/land/withdraw, observation add, validation add, assessment add, input-request open/respond, endorse, fact port, and store remove/gc/compact), and the Inspector's store chip surface a one-line advisory pointing at pointbreak store link <slug> — the split is signalled, never silent. Write verbs print it on stderr after a successful write, from one shared CLI seam; it never fails the command. Before any family write, link runs its gates in order: it refuses an ephemeral worktree (override --include-ephemeral) and a sensitivity-flagged worktree (override --include-sensitive), refuses a slug already stamped for a different family, and warns (without blocking) on a sync-managed filesystem path or when the clone shares no git history with an existing family. It then folds the clone-local <git-common-dir>/pointbreak history forward with independent verification and flips the binding last, so an interrupted link leaves the clone still resolving its clone-local store. Omitting <slug> fails with a suggestion rather than picking one silently. --retire-source then retires the clone-local store: it deletes only the record files an independent re-verification proved present in the family store, plus disposable rebuildable data, and never deletes recursively. It keeps the store directory and its authority lock file, so a leftover directory holding only authority.writer.lock is expected; sourceRetired is true when nothing else remains (see storage-model.md). It refuses with an error whose message begins source_busy; while another Pointbreak writer holds the clone-local store, and refuses — naming the entry, deleting nothing, and leaving the clone unlinked — when the store holds an entry retirement does not verify, such as operations/. A record that appears while retirement is checking is kept: nothing is deleted, sourceRetired is false, and a source_retirement_residue diagnostic asks for a rerun. Do not run family-store maintenance such as pointbreak store forget during a retire. The link writer is not executable in this build. When the fold carries prior unsigned pointbreak store remove events, a diagnostic discloses that they lost possession-based suppression and should be re-issued in the family store. It emits pointbreak.store-link JSON (familyRef, cloneRef, createdFamily, the folded* counts, sourceRetired, and any warnings). pointbreak store unlink detaches this clone (clearing the binding and deregistering it) without moving any data, and survives a family store that was already forgotten.

pointbreak store forget <slug> is the whole-store destructive verb for a family store, deliberately outside pointbreak store remove's content-targeted removal (no store survives a forget to hold a removal event). It is dry-run by default: it previews the inventory and live-clone count that would be lost and deletes nothing. --yes performs the deletion, but only for a family with zero live clones (an orphaned family store — a different notion from pointbreak store remove --unreachable, which targets unreachable-commit content); a family with live clones additionally requires --force. pointbreak store list is the one repo-less surface: it takes no --repo flag, never resolves a git repo, and walks <pointbreak-home-root>/stores/ reporting each family's familyRef, inventory, liveCloneCount, orphaned flag, and lastWrite. Against an empty home it returns an empty families array.

pointbreak store remove retires content-addressed artifacts from the store. It resolves exactly one selector to a set of content hashes — --snapshot <id> (a snapshot's bound artifact), --revision <id> (every artifact a revision references), --ref <name> / --range <a>..<b> (artifacts of revisions anchored on the named commit or commit range), or --unreachable (artifacts of commit-anchored revisions whose commits are all unreachable from live refs; --orphans is a deprecated alias) — and records one removal fact per content hash. It emits pointbreak.store-remove JSON listing each contentHash, whether it was newly created, and coReferencingUnits (other revisions that still name the same shared artifact, reported before the removal), plus eventsCreated and eventsExisting. Removal is content-targeted and idempotent: re-removing a hash reports created: false. Removal is a write, so a signed store stays signed — --sign-key selects the signing key exactly as pointbreak capture does. There is deliberately no --idempotency-key; the removal key is derived solely from the content hash. Removal records the fact; it does not delete bytes — run pointbreak store gc / pointbreak store compact to reclaim them.

pointbreak store gc and pointbreak store compact are the same local sweep: they physically delete the content-addressed blobs whose content hash has been removed, reclaiming disk. The sweep records no event and is fully re-derivable from the log — re-capturing the same content re-materializes the blob. It emits pointbreak.store-compact JSON listing each swept blob's contentHash and outcome (removed or missing) plus bytesReclaimed. Running it again is a no-op (every removed blob is already missing).

Removed content renders as an explained state on every read surface, never as an error. For note-shaped bodies (observation and input-request bodies, response reasons, assessment and validation summaries, imported note bodies), pointbreak revision show, the leaf list/fetch/show commands, and pointbreak history omit the body text and carry a bodyContentState / summaryContentState / reasonContentState field beside the content hash — suppressed_present while the bytes are still stored (a compact would reclaim them) or physically_removed after the sweep — plus body_content_suppressed_present / body_content_physically_removed diagnostics. The field is omitted entirely while content is present, and a body that is missing without a recorded removal still fails the read with the import referenced artifacts guidance.

Command output is the machine-integration surface, under the tiered stability promise described at the top of this reference (a frozen hard core; an additive-evolvable soft shell). Raw store paths, event files, artifact paths, .git paths, and .pointbreak/data paths remain internal storage details.

pointbreak identity

# Preview the actor that repository writes will use (pointbreak.identity-whoami).
pointbreak identity whoami [--repo .] [--format <fmt>]

# Stage a delegation record binding an agent to its responsible principal (pointbreak.identity-delegate).
pointbreak identity delegate <agent-actor-id> --principal <principal-actor-id> \
  [--from <RFC3339>] [--until <RFC3339>] [--comment <text>] [--local] [--repo .] [--format <fmt>]

# Stage an actor-attributes entry — kind + roles — for any actor (pointbreak.identity-attest).
pointbreak identity attest <actor-id> --kind <kind> [--role <role>]... \
  [--comment <text>] [--local] [--repo .] [--format <fmt>]

pointbreak identity whoami previews the writer identity that the existing resolver will use. It honors POINTBREAK_ACTOR_ID, then Git email, Git name, and finally actor:local; it accepts no actor override. Its v1 JSON is exactly schema, version, and actorId.

The other pointbreak identity commands write the actor/principal config the read side (above) resolves. Both are possession-style: they stage the working-tree edit only and never invoke git — review and commit the file to apply it (git log -p is the audit trail), exactly like pointbreak key enroll.

  • delegate stages a delegation record into .pointbreak/delegates.json binding <agent-actor-id> (an actor:agent:<name> id) to a responsible non-agent --principal (the human/actor that answers for the agent; the depth-0 rule rejects an agent principal). --from defaults to now in RFC 3339 UTC; --until defaults to an open window; --comment is free text for diff readers. Emits a pointbreak.identity-delegate document and a stderr hint to commit.
  • attest stages an actor-attributes entry into .pointbreak/actor-attributes.json for <actor-id> (any persisted actor id). --kind is required — exactly one kind per actor; the reserved well-known kinds are human, agent, service, and reviewer-model, but any lowercase-kebab token is accepted. --role is repeatable; kind and roles are normalized to lowercase-kebab and roles are deduped + sorted. Re-attesting replaces the actor's entry (kind, roles, and comment) — it is not additive. Emits a pointbreak.identity-attest document.
  • --local writes the private .local.json sibling instead of the committed file and git-excludes it via the generated, committed .pointbreak/.gitignore (its *.local.json line covers every private override). The layers merge git-config style: a local entry fully replaces the committed entry for that key on this machine (never a merge), and the command surfaces that full-replace caveat on stderr.
  • --repo (default .) may be the repository root or a path inside it; the entry always lands at the worktree-root .pointbreak/. Inputs are validated against the same grammar the readers enforce, so a staged file always re-reads and a rejected input writes nothing.

The delegation-map format is documented in storage-model.md; the models and decisions are in ADR-0010 (delegation) and ADR-0012 (actor attributes).

pointbreak key

Manage the user-level signing keystore and stage signer enrollment. Keys live in ~/.pointbreak/keys/ (honoring $XDG_DATA_HOME on Unix and %APPDATA%\pointbreak on Windows; POINTBREAK_HOME overrides) — never in the repo .pointbreak/ or the store. See storage-model.md for the key home and allowed-signers format.

# Generate a human signing key and print its did:key (pointbreak.key-init).
pointbreak key init --name default

# List local keys with enrollment status and which is the default (pointbreak.key-list).
pointbreak key list --repo .

# Discover local Git/OpenSSH signing evidence (pointbreak.key-discover).
# Discovery only suggests reviewed next steps.
pointbreak key discover --repo .

# Print a key's did:key and/or raw public key (pointbreak.key-show).
pointbreak key show default --did
pointbreak key show default --pubkey

# Adopt an existing SSH Ed25519 key as an agent-backed signer (pointbreak.key-use-ssh).
# Reuses ssh-agent custody — no new key material. Parallel to `init`.
pointbreak key use-ssh ~/.ssh/id_ed25519.pub --name default
pointbreak key use-ssh 'key::ssh-ed25519 AAAA…'   # git user.signingKey literal form

# Stage an allow-list entry binding a key's did:key to an actor (pointbreak.key-enroll).
# Possession-style: this stages the working-tree .pointbreak/allowed-signers.json edit only;
# review and commit it to authorize the binding.
pointbreak key enroll default --actor actor:agent:claude-code --repo .
pointbreak key enroll --signer did:key:z6Mk... --actor actor:git-email:alice@example.com --repo .

init refuses to overwrite an existing named key. use-ssh adopts an existing SSH public key as an agent-backed default signer: it accepts a *.pub path or a key::ssh-ed25519 AAAA… literal, emits a pointbreak.key-use-ssh document with the derived did:key (the same .didKey field pointbreak key show --did prints) plus an enrollment hint, and (like init) refuses to overwrite. Only plain ssh-ed25519 keys are accepted; ed25519-sk/RSA/ECDSA are rejected with a clear error pointing at pointbreak key init. discover reads local Git/OpenSSH signing evidence and emits a pointbreak.key-discover document: candidates[] includes source, signerId, keyArgument, suggestedName, actorHints, matching localKeys, matching enrolledActors, the resolvedActor used for suggestions, and advisory commands; diagnostics[] reports non-fatal missing or unsupported evidence with source details. Suggested commands describe unmet setup only: an already adopted signer is not offered a duplicate use-ssh alias, and an already authorized actor/signer pair is not offered a redundant enroll command. This discovery does not authorize keys, does not write the key home, and does not stage .pointbreak/allowed-signers.json. Review a candidate, optionally adopt public key custody with pointbreak key use-ssh, then stage reviewed trust with pointbreak key enroll --signer <did:key> --actor <actor> --repo ..

list/enroll/discover take --repo (default .) to resolve the committed .pointbreak/allowed-signers.json or local Git/OpenSSH evidence. Enrollment never commits — the human's commit is the authorization.

Each write subcommand (capture, observation add, assessment add, validation add, association record/withdraw, input-request open/respond) accepts --sign-key <name|path> to sign that write with a specific key (highest precedence; overrides POINTBREAK_SIGNING_KEY). A key that cannot be loaded leaves the write unsigned at exit 0 with an advisory diagnostic — signing never blocks. An agent-backed key resolves through an identities-only ssh-agent pre-flight; if the agent is unavailable (signing_agent_unavailable), does not hold the key (signing_agent_key_absent), or fails the real sign (signing_agent_sign_failed), the write is left unsigned at exit 0 — see signing-ux.md for the full never-gates table. This never-gates behavior covers the ordinary signed review writes listed above; pointbreak endorse is the exception, where an unresolved signer is a hard error rather than an unsigned write. Only shipped subcommands are listed; rotate and revoke are named follow-ons, not yet available.

pointbreak observation

pointbreak observation add --track <track-id> --title <title> \
  [--review-cursor <token> | --revision <revision-id> | --exact-revision <revision-id>] [target options] \
  [--body-content-type text/plain|text/markdown] \
  [--tag <tag>]... [--confidence low|medium|high] [--supersedes <observation-id>]... \
  [--responds-to <observation-id>]...
pointbreak observation list [--revision <revision-id>] [--track <track-id>] \
  [--exact-revision <revision-id>] \
  [--file <path>] [--tag <tag>] [--include-body] [--format <fmt>]

Observations are append-only review notes for a captured revision.

  • observation add requires --track and --title.
  • Change-capable writers use --review-cursor so the exact Change/Revision/artifact, graph, and source state are revalidated immediately before append. --exact-revision is the low-level exact target; --revision retains legacy proposal-supersession selection and does not follow Change replacement: when it names a Revision that a Change has replaced, the write is refused with revision_replaced_by_change, which names the current Revision(s); pass --review-cursor to write to the current Revision or --exact-revision to address the replaced one deliberately. The refusal is decided on the writer-visible store-wide event snapshot loaded before the append; it is not re-checked under the store's authority lock at append time, so a replacement relation another writer appends after that snapshot does not refuse the write (#837). The three options are mutually exclusive.
  • Tracks are review lanes, not actor or producer provenance.
  • Without --file, the observation targets the whole revision.
  • With --file <path>, it targets a captured file.
  • With --file <path> --start-line <n> [--end-line <n>], it targets a range on --side <old|new> where the default side is new.
  • Bodies may come from --body, --body-file, or --body-stdin.
  • --body-content-type defaults to text/plain; use text/markdown when the body should render as Markdown in the inspector.
  • Large bodies are stored as Pointbreak-owned shore.note-body artifacts while command output keeps artifact paths private.
  • --supersedes <observation-id> (repeatable) records a correction by appending a new observation that names the older observation.
  • --responds-to <observation-id> (repeatable) records that this observation responds to an existing observation — a fact-to-fact relationship (a derived responded_by back-pointer is surfaced on the target). It does not supersede or mutate the target.
  • --confidence <low|medium|high> records an optional confidence level on the observation.
  • --tag <tag> (repeatable) attaches free-form tags used by the observation list --tag filter.
  • observation list replays durable events for the revision and may filter by revision, track, file, or tag. It hydrates body text only with --include-body.

Output is compact pointbreak.review-observation-add or pointbreak.review-observation-list JSON by default.

pointbreak input-request

pointbreak input-request open --track <track-id> --title <title> --reason <reason> \
  [--review-cursor <token> | --revision <revision-id> | --exact-revision <revision-id>] \
  [--mode operative|advisory] \
  [--body-content-type text/plain|text/markdown]
pointbreak input-request list [--revision <revision-id> | --exact-revision <revision-id>] [--track <track-id>] \
  [--mode operative|advisory] [--file <path>] [--status open|responded|ambiguous|all] \
  [--include-body] [--format <fmt>]
pointbreak input-request show <input-request-id> [--include-body]
pointbreak input-request respond <input-request-id> --outcome <outcome> [reason options] \
  [--reason-content-type text/plain|text/markdown]

Input requests are durable pause or decision requests for a captured revision.

  • input-request open requires --track, --title, and --reason.
  • --reason classifies the ask. Values: ambiguous-state, unsafe-action, stale-revision, failed-gate, external-side-effect, conflicting-event, missing-permission, manual-decision-required, insufficient-evidence. insufficient-evidence types an ask for more evidence — a debugger or CI run can satisfy it with validation evidence. The set grows additively within version:1 (a new value is appended, not a version bump); see the hard-core note above.
  • Change-capable writers use --review-cursor; --exact-revision is the low-level exact target and --revision retains legacy proposal-supersession selection without following Change replacement: naming a Revision that a Change has replaced is refused with revision_replaced_by_change, which names the current Revision(s) and the two exact selectors (decided on the pre-append snapshot, as for observation add). Without a selector, the command defaults to the single captured Revision and errors if several are in scope.
  • --mode defaults to operative; advisory requests are durable and visible but do not imply a cooperative client must pause. The mode (operative/advisory) and reasonCode values surface on the consumed input-request list field-paths, so — like the response outcomes below — they are part of the frozen hard core: stable within version:1, changed only by a coordinated version bump.
  • Targets mirror observations: review-wide by default, captured file, captured range, or an existing native observation through --observation <observation-id>.
  • Request bodies may come from --body, --body-file, or --body-stdin.
  • --body-content-type defaults to text/plain; use text/markdown when the request body should render as Markdown in the inspector.
  • Large request bodies reuse Pointbreak-owned shore.note-body artifacts while command output keeps artifact paths private.
  • input-request list is the V1 polling read surface and defaults to open requests. It may filter by revision, track, mode, file, or status, and hydrates body text only with --include-body.
  • input-request show <id> --include-body returns one request and hydrates the body when requested.
  • input-request respond <id> appends an input_request_responded event.
  • Response reasons may use --reason-content-type text/markdown; the default is text/plain.
  • Response outcomes are approved, rejected, dismissed, superseded, and abandoned. These wire values are part of the frozen hard core (review-loop drivers branch on them): stable within version:1, changed only by a coordinated version bump.

Output documents are compact pointbreak.review-input-request-open, pointbreak.review-input-request-list, pointbreak.review-input-request-show, and pointbreak.review-input-request-respond JSON by default.

V1 is durable and polling-friendly. It does not add a daemon, filesystem watch mode, TUI prompt, notification transport, or cancellation/escalation event.

pointbreak assessment

pointbreak assessment add --track <track-id> --assessment <assessment> \
  [--review-cursor <token> | --revision <revision-id> | --exact-revision <revision-id>] [target options] \
  [--summary-content-type text/plain|text/markdown]
pointbreak assessment show [--revision <revision-id> | --exact-revision <revision-id>] \
  [--all] [--track <track-id>] \
  [--include-summary] [--format <fmt>]

Assessments record review calls for a captured revision.

  • assessment add requires --track and --assessment.
  • Change-capable writers use --review-cursor so the selected exact state is revalidated before append. --exact-revision is the low-level exact target; --revision retains legacy proposal-supersession selection without following Change replacement: naming a Revision that a Change has replaced is refused with revision_replaced_by_change, which names the current Revision(s) and the two exact selectors (decided on the pre-append snapshot, as for observation add). The three options are mutually exclusive.
  • CLI input uses kebab-case assessment values: accepted, accepted-with-follow-up, needs-changes, and needs-clarification. Command JSON output uses the matching snake_case values: accepted, accepted_with_follow_up, needs_changes, and needs_clarification. The snake_case wire values are part of the frozen hard core (review-loop drivers branch on them): stable within version:1, changed only by a coordinated version bump.
  • Targets mirror the revision ledger: review-wide by default, captured file, captured range, native observation, native input request, or another assessment.
  • Summaries may come from --summary, --summary-file, or --summary-stdin.
  • --summary-content-type defaults to text/plain; use text/markdown when the summary should render as Markdown in the inspector.
  • Large summaries reuse Pointbreak-owned shore.note-body artifacts while command output keeps artifact paths private.
  • --replaces <assessment-id> is the only V1 relationship that removes an older assessment from the current set.
  • --related-observation and --related-input-request record evidence links; they do not mutate observations or close input requests.
  • assessment show reports current status as unassessed, resolved, or ambiguous. It may filter by revision or track, include replaced assessments with --all, and hydrate summaries with --include-summary.

Output documents are compact pointbreak.review-assessment-add and pointbreak.review-assessment-show JSON by default.

State-change outcomes such as deferred, split-out, overridden, and superseded are ordinary review observations when needed.

pointbreak attention

This is the item-level attention document: one entry per outstanding fact, anchored to its exact Revision. pointbreak change attention is its complement, not its summary: the Changes whose lifecycle is not yet accepted, with current-set topology and exact fact origins. Neither is derivable from the other. A freshly captured Revision nobody has assessed is no item, yet its Change is awaiting a call; an advisory ask, or a failed check on an already accepted Change, is an item that puts no Change in change attention. An empty item list is therefore not an all-clear, and the text digest says so by closing with a pointer to pointbreak change attention.

Both read replacement from the same authority, at different scope. On a store that holds Change claims a Revision is superseded when the Changes that hold it replace it, and a proposal-borne supersedes list is historical input that decides freshness only on a store with no Change claims. Item attention applies that store-wide (a Revision stays current while any Change holding it still has it current); Change lifecycle and the attention_wait order follow each Change's own replacement. Replacement retires a replaced Revision's failed checks and qualifying call inside that Change, not its open requests: those still need a response, and an operative one keeps the Change in progress.

pointbreak attention list [--repo <path>] [--revision <revision-id>] [--format <fmt>]

attention list is a read-only projection of the review record's outstanding, judgment-needing state — the first product surface of "Pointbreak surfaces the moments that need judgment." It guides, never gates (ADR-0019): nothing here is a write precondition. The emitted document is pointbreak.attention-list, version 1.

With a current active derived profile, the command reads the incrementally maintained attention projection and carries projectionStamp; otherwise it reads authoritative journal data and carries eventSetHash. The item and filter fields are identical in both cases.

  • --repo defaults to .; --revision scopes the read to one revision — its anchored items plus the competing-heads thread that covers it (a short id resolves via the shared id resolver).
  • Each item carries a kind-qualified id, a tier (primary or secondary), the anchoring revisionId (absent only for thread-scoped competing_heads), a replacement-derived freshness block, an observedAt stamp, and a kind-tagged detail. A Revision replaced in one Change but still current in another stays current: it is still a live candidate somewhere. --revision scope is exact, so a replaced Revision's items appear under its own id (marked superseded), never under its successor's. Items sort by tier, then oldest observedAt first, then id.
  • Item kinds:
    • open_input_request — an open ask (operative → primary, advisory → secondary).
    • ambiguous_assessment — more than one current assessment on a revision, carried as peers; on a superseded revision the item resolves once every successor head has been re-judged.
    • competing_heads — a proposal-borne supersession thread with two or more current heads, on a store with no Change claims. headRevisionIds is sorted for determinism, not a priority ranking. Once a store holds Change claims this kind no longer occurs: replacement divergence inside a Change reads as conflicted in pointbreak change attention, and two Changes that independently replace a shared Revision do not compete.
    • stale_assessment — a current assessment anchored to a superseded revision, until every current head of the thread has been re-judged. headRevisionIds names that complete current head set; freshness.supersededBy continues to name direct superseders only.
    • failed_validation — the latest failed/errored check per (revision, track, checkName) on a current head; a strictly-later passing rerun clears it (skipped never clears), and so does a later, unanimously accepting judgment on the revision (ADR-0019's judgment-subsumption amendment).
    • follow_up_outstanding — an accepted-with-follow-up assessment whose linked requests are still open.
  • This document is entirely soft shell: no field-path here joins the ADR-0029 hard core.

pointbreak summary

pointbreak summary show [--repo <path>] [--receipt digest|entries] [--format <fmt>]
pointbreak summary check <file> [--repo <path>] [--format <fmt>]

summary show describes the recorded review cycles in one store: how many captured Revisions each Change went through, what the first capture's verdict was, and how much of the captured work carries an assessment or a commit association. It is a read-only projection: it records nothing, is never recorded itself, and gates nothing. The figures describe a store, not the people who wrote to it, and are advisory. The emitted document is pointbreak.review-summary, version 1.

Every figure is a count with its denominator. A measure with nothing to count is {"state":"unavailable","reasons":[…]}, never 0; the document carries no ratio, percentage, or score field. (--format text may print a whole percentage next to a nonzero denominator; that is a rendering only.) No actor id, signer, key, email, or track appears in the document.

Population. A Change is seen when it has at least one membership claim. It is a review Change when at least one of those claims is not migration backfill. Migration backfill is identified by the store's signed activation record: the store migration names every record it wrote in the activation's manifest, by the same key the record's id is derived from, so exactly those records are backfill. A store without an activation record excludes nothing and says so. Every membership of a review Change counts, including backfill-written ones. A membership is current until a withdrawal names it; a review Change with no current membership is excluded as noCurrentMembers rather than dropped. The remaining Changes are counted, and their current-member Revisions are the captured Revisions. population reports these counts, the observed capture window, and both exclusions with their sizes (migrationBackfill names its basis: storeActivationManifest with manifestHash, or noActivationManifest). Membership and captured-Revision counts range over counted Changes, current and historical.

reviewRounds. profile is the number of distinct current-member Revisions per counted Change, as a distribution. A round is one captured cycle, not a judgment of the work. firstCapture gives one result per counted Change from its earliest-captured Revision (by capture instant, legacy and RFC 3339 timestamps compared as instants, ties by Revision id): unassessed when it has no live verdict (one that no later assessment replaces), otherwise needsChanges if any live verdict is needs_changes, else accepted if any is accepting, else otherVerdict.

recordInternalMeasures measure the record against itself, denominated in captured Revisions, and say nothing about landed work:

  • assessedCaptureShare — captured Revisions with at least one assessment, replaced or not. A file-, range-, or observation-scoped assessment counts for its Revision.
  • commitAssociatedCaptureShare — captured Revisions with at least one commit association. Withdrawn associations still count here.
  • firstCaptureAcceptance — accepted first captures over first captures carrying a live verdict.
  • actorDistinctAssessmentShare — per captured Revision: actorDistinct when some assessment was recorded under a different actor id than the capture, actorSame when every one shares it, undetermined when there is no assessment or no capture record. Actor ids are asserted, not verified identity; keyEvidence is reported separately and is unavailable because signing keys are not compared.

landedWorkCoverage always lists six rungs — tipExact, associatedRange, assessedRange, acceptingVerdictRange, distinctIdentity, provedLanding — denominated in commits on the integration branch (provedLanding in associations). This read does not walk the integration branch history, so each rung is unavailable with reason integrationRefNotWalked (and signingKeysNotRead on distinctIdentity). The two blocks share no field name.

provenance. basis says which read answered. When the derived profile is active and current, the summary is read from it: basis is projection and projectionStamp names that local index snapshot. The stamp identifies disposable local state, not the facts counted. Otherwise basis is factSet and eventSetHash identifies the store's facts; with the derived profile active but its generation absent, rebuilding, catching up, or moved during the read, the command prints one pointbreak store derived build hint per store and process and still succeeds. The read never builds or catches up the generation. On either basis the figures are the same and the receipt below is computed from the counted facts' recorded bytes, each re-read from its stored record, so it means the same thing on both. eventCount is the number of facts the read covered; metricDefinitions names the definitions above; computedAt is when the read ran.

Counted-input receipt. provenance.countedInputs names exactly the facts the measures consumed for the counted population: the membership claims of counted Changes and the withdrawals naming them, the captures of captured Revisions, the assessments on captured Revisions and the assessments replacing them, and the commit associations on captured Revisions. Each entry has four fields:

  • eventId — commits to the write's idempotency key, not to its content;
  • payloadHash — commits to the payload;
  • eventRecordHash — commits to the record apart from its signatures and transport fields;
  • verificationStatus — how the reader's allowed-signers file verifies the record's signature (valid, untrusted_key, invalid, or unsigned). It depends on the reader's trust set and is outside the digest.

digest is sha256 over the lines eventId SP payloadHash SP eventRecordHash LF, sorted by eventId then eventRecordHash (algorithm: shore.event-set.canonical-map.v1). By default the receipt carries the digest, count, per-kind counts, and the verification tally (with allowedSignersConfigured); --receipt entries also inlines every entry. The receipt proves which facts were counted, never that the store is complete (completeness: notProven); a receipt minted after a rewrite commits to the rewritten bytes, so keep a copy outside the store for it to mean anything.

On a store that has not completed its migration, summary show refuses like every other ordinary read.

pointbreak summary check

summary check <file> re-checks the receipt in a saved summary against the store as it is now. Save the summary with --receipt entries (pointbreak summary show --receipt entries > summary.json); a document with only the digest has nothing to re-check, and the command says so. The emitted document is pointbreak.review-summary-check, version 1. Like summary show it is a read-only projection: it records nothing and gates nothing, and it exits successfully whenever the check ran, so a difference is data for you to read, not a process failure.

Each listed entry is compared with the event of the same eventId in the store:

  • matched — the event is present with the recorded payloadHash and the same eventRecordHash, recomputed from the stored record now;
  • changed — the event is present but its payload or its record differs. Editing only a field outside the payload (such as the recorded producer version) still changes the record hash, so a rewrite that keeps the payload hash consistent is still caught, with no signing key required;
  • missing — the store holds no event with that id.

differing lists the changed and missing entries with the recorded hashes and, for changed, the current ones. digestMatchesEntries reports whether the saved file's entries still reproduce its own digest, which catches an edited receipt file. verificationStatus is not compared: it depends on the reader's allowed-signers file.

The check proves only the facts the receipt lists (completeness: notProven). Events added to or removed from the store elsewhere are out of its reach, and a receipt minted after a rewrite commits to the rewritten bytes.

pointbreak validation

pointbreak validation add --track <track-id> --check-name <name> --status <status> \
  [--review-cursor <token> | --revision <revision-id> | --exact-revision <revision-id>] \
  [validation options] \
  [--summary-content-type text/plain|text/markdown]
pointbreak validation list [--revision <revision-id>] \
  [--exact-revision <revision-id>] \
  [--track <track-id>] [--status <status>] [--include-body] [--format <fmt>]

Validation checks record local test, lint, build, or other verification evidence for a captured revision. They are advisory review context only: they do not accept, reject, merge, block, or replace a review assessment.

  • validation add requires --track, --check-name, and --status.
  • Change-capable writers use --review-cursor so the selected exact state is revalidated before append. --exact-revision is the low-level exact target; --revision retains legacy proposal-supersession selection without following Change replacement: naming a Revision that a Change has replaced is refused with revision_replaced_by_change, which names the current Revision(s) and the two exact selectors (decided on the pre-append snapshot, as for observation add). The three options are mutually exclusive.
  • Validation targets are revision-only. There are no file or path target flags.
  • Status values are passed, failed, errored, and skipped.
  • --command, --exit-code, --source-fingerprint, --started-at, --completed-at, and repeatable --log-content-hash record evidence metadata without exposing artifact paths.
  • --trigger defaults to manual; accepted values are manual, push, and pull-request.
  • Summaries may come from --summary, --summary-file, or --summary-stdin.
  • --summary-content-type defaults to text/plain; use text/markdown when the summary should render as Markdown in the inspector.
  • Large summaries reuse Pointbreak-owned shore.note-body artifacts while command output keeps artifact paths private.
  • validation list replays durable events for the revision and may filter by revision, track, or status. It hydrates summaries only with --include-body.

Output documents are compact pointbreak.review-validation-add and pointbreak.review-validation-list JSON by default.

pointbreak fact

pointbreak fact port --origin-revision <revision-id>@<object-artifact-sha256>
  --origin-fact <observation-id|input-request-id> --review-cursor <token>
  --relation context-only|reanchored-as|carried-open-as|resolved-by
  [--target-fact <observation-id|input-request-id>] [--rationale-content-hash <sha256>]
  --track <track-id> [--repo <path>] [--format <fmt>]

fact port records explicit continuity from an observation or input request owned by one exact Revision to the exact Revision selected by a validated review cursor. reanchored-as and carried-open-as require a target fact; the other relations forbid one. The origin fact keeps its original ownership: the port is context, not reassignment. Validation and assessment facts cannot be ported, so accepting judgments and check results never leak across captured content states.

pointbreak endorse

pointbreak endorse <target-event-id> [--sign-key <name|path>] [--actor <id>] [--repo .] [--format <fmt>]

pointbreak endorse records a detached co-signature (an endorsement) over an existing target event — for example a captured revision's work_object_proposed event. The resolved signer is the attesting signer and the carrier's envelope writer is the endorser's own actor (--actor, else the resolved writing identity), never the target's author.

  • Unsigned is a hard error. Unlike every other write — where signing never gates — an endorsement has no unsigned form, because the signature is its content. The signer is resolved first (before the target); if none resolves (POINTBREAK_SIGNING=off, no key, an unreadable key), the command exits non-zero and writes nothing. Signer precedence otherwise follows the Signing rules above.
  • Idempotent: re-endorsing the same target with the same signer is a no-op (eventsCreated: 0, eventsExisting: 1, same carrier eventId).
  • The emitted pointbreak.review-endorse document reports carrier facts (eventId, targetEventId, targetEventRecordHash, attestingSigner, actorId, and write counts) — not a trust verdict. Whether an endorsement classifies as trusted is reader-relative (resolved against the reader's allow-list at read time), not stamped at write time.

The endorsement record and its read-side classification are decided in ADR-0013.

pointbreak association

pointbreak association record --track <track-id> (--commit <rev> | --ref <name> --head <oid>) \
  [--revision <revision-id> | --exact-revision <revision-id> | --review-cursor <token>] \
  [--sign-key <name|path>] [--repo <path>]
pointbreak association land --review-cursor <token> --track <track-id> --commit <rev> \
  [--allow-extension | --provenance-only | --candidate-parent] \
  [--dry-run] [--expect-proof <hash>] [--sign-key <name|path>] [--repo <path>]
pointbreak association withdraw <association-id> --track <track-id> \
  [--revision <revision-id> | --exact-revision <revision-id> | --review-cursor <token>] \
  [--sign-key <name|path>] [--repo <path>]
pointbreak association list [--revision <revision-id>] [--axis commit|ref] [--current] \
  [--repo <path>] [--format <fmt>]

pointbreak association records and withdraws structural commit-graph associations of an exact Revision as append-only associate/withdraw events on two axes — commit and ref. A structural record says only that the named Git object is associated with the Revision; it does not claim byte equality, containment, or review coverage. Use association land for proof-backed landing language.

After committing an accepted worktree capture, select a commit-bound cursor before landing. The original authoring cursor is worktree-bound and intentionally becomes stale when the commit changes that source state:

landing_cursor=$(pointbreak change select <change-id> \
  --revision <revision-id> --source commit:<oid> \
  --format json | jq -r '.token')
pointbreak association land --review-cursor "$landing_cursor" \
  --track <track-id> --commit <oid>
  • record takes exactly one axis. --commit <rev> (resolved to an OID) binds the revision on the commit axis; --ref <name> (a short branch name is normalized to its full ref) at the explicit --head <oid> (never inferred) binds it on the ref axis. --commit and --ref are mutually exclusive, and --ref requires --head.
  • land validates the exact review cursor, computes and durably records the Revision-to-commit proof first, then records the commit association and final attestation. Exact equality is accepted by default. --allow-extension admits a proved extension while reporting unreviewed additions. --provenance-only records honest attribution without claiming content equivalence. Refuted or indeterminate proof never receives strong landing wording.
  • withdraw <association-id> retracts an earlier association by its id. The id is positional and must carry its prefix — assoc-commit:… or assoc-ref:… — because the prefix selects which axis is withdrawn; a prefixed short form like assoc-commit:<hex-fragment> resolves against the store. Withdrawal is terminal: a later re-association of the same target does not revive the withdrawn edge.
  • Both writes are signable — --sign-key <name|path> selects the signing key exactly as pointbreak capture does, and signing never gates the write.
  • --exact-revision pins the named captured Revision and --review-cursor additionally revalidates its Change graph before writing. Legacy --revision retains head-seed behavior. Without a selector, the command defaults to the single captured Revision and errors if multiple candidates exist.
  • list reports both axes unless --axis commit|ref narrows to one, and --current excludes withdrawn associations, showing only what currently holds. It emits pointbreak.review-association-list JSON.
  • The write forms emit pointbreak.review-association-commit, pointbreak.review-association-commit-withdrawn, pointbreak.review-association-ref, and pointbreak.review-association-ref-withdrawn JSON with the new association id and write counts.

Single-commit rewrites and read-only preview

Situation Route Evidence boundary
Commit materializes the same reviewed state against its original base Fresh --source commit:<oid> cursor, ordinary association land Existing exact-materialization proof
One commit replays an identical scoped delta on a descendant base --source captured, then --candidate-parent --dry-run, then record with --expect-proof Verified scoped equivalent rewrite; original review facts stay historical
Changed blobs, modes, paths, status, kind, or included scope Capture and review a replacement Revision in the same Change Fresh validation and assessment
Root/merge candidate, multi-commit source, staged/unstaged/root capture, non-commit base, unrelated or unavailable history Use an applicable ordinary route or capture/review a replacement Revision Parent-relative mode refuses
Provenance only, without content equivalence Structural association record or ordinary land --provenance-only No content-qualified claim

--candidate-parent admits only combined worktree captures or a committed range whose source commit has exactly one parent equal to the captured base A. The candidate C′ must have exactly one actual commit-object parent B, and A must be an ancestor of B (equality is allowed). It compares the frozen artifact's canonical entries with B..C′ using the original capture mode and path scope. Full old/new blob identities, modes, paths, status and content kinds must match, including untracked-add normalization. An identical text hunk with different before/after blobs fails. Changes outside an explicitly captured path scope are outside this claim. Advancing the base produces equivalent rewrite, not exact materialization. This mode cannot combine with --allow-extension or --provenance-only. Candidate resolution, parent/tree identity, ancestry, candidate diff and structural endpoint recording ignore Git replacement objects in this mode. Ordinary capture and landing retain their configured behavior. The policy is local to each read; it does not change process environment or repository settings.

With an existing exact Change/Revision and an eligible committed candidate, run:

candidate=$(git rev-parse --verify 'HEAD^{commit}')
rewrite_cursor=$(pointbreak change select "$change_id" \
  --revision "$revision_id" --source captured --format json | jq -r '.token')
pointbreak association land --review-cursor "$rewrite_cursor" --track "$track" \
  --commit "$candidate" --candidate-parent --dry-run --format json > rewrite-preview.json
proof_hash=$(jq -er '.proof.evidenceSha256' rewrite-preview.json)
pointbreak association land --review-cursor "$rewrite_cursor" --track "$track" \
  --commit "$candidate" --candidate-parent --expect-proof "$proof_hash"

--dry-run also works on the ordinary route. It returns pointbreak.association-land-preview.v1 with exact Revision, commit/tree OIDs and the full canonical proof. It performs no write-store preparation, signing-key load, artifact/event publication, migration, rebuild or activation. There is no write acknowledgement or created/landed claim. Preview does not require --expect-proof, but checks it when supplied: a mismatched hash refuses without writing anything. Recording in parent mode requires the hash emitted by the current preview. Any supplied expected hash on ordinary preview or recording is checked too. Preview JSON is evidence for inspection, never trusted input. Recording recomputes the proof, revalidates graph/artifact and resolves the candidate again immediately before publication. Drift refuses before publishing a new proof, association or attestation. Git and the Journal remain separate authorities; there is no transaction excluding arbitrary external mutation. The writer uses the resolved commit OID and retains ordered, idempotent proof → association → attestation publication, truthful partial failures, write acknowledgements and advisory post-truth refresh diagnostics.

A captured cursor is safe here because the independent canonical comparison binds the candidate. It does not permit recording candidate tests or assessments against the old Revision. Original Accepted and validation facts still describe the original captured bytes. Retain candidate validation externally: record exact candidate commit, tree, parent, proof hash, environment/tool identities, commands, result, and attempt identity. This slice adds no candidate-validation command or automatic readiness decision. Upstream changes may still require reviewer attention even when the scoped proof succeeds.

Existing associations remain historical; each proof qualifies one association. Multiple live associations can remain ambiguous, and no whole-tree equivalence follows from a scoped proof. No derived rebuild or new stored schema/capability is required. Push, PR creation and merge need their own authorization. Broader multi-commit rewriting, automatic readiness and candidate-validation storage remain outside this #747 slice.

Divergent or dangling associations surface as advisory diagnostics on the read surfaces (divergent_commit_association when two or more distinct current commit OIDs claim one revision; retraction_target_missing when a withdrawal names an association that never appeared); they are render-only and never gate a write.

pointbreak history

pointbreak history [--repo <path>] [--revision <id>] [--track <track-id>] \
  [--event-type <event-type>]... [--ref <name> [--by label|liveness]] \
  [--filter <query>] [--limit <n>] [--cursor <cursor>] [--watch [--poll-ms <ms>]] \
  [--include-body] [--format <fmt>]

pointbreak history reads the chronological ledger of durable Pointbreak events.

  • History emits compact pointbreak.review-history v1 JSON by default. A bounded --limit or --tail request uses a current active derived generation when --filter, --ref, and --watch are absent; typed revision, track, event-type, and selected-body hydration remain supported on that route.
  • A derived page carries projectionStamp; an authoritative page carries eventSetHash. eventCount describes the complete validated event population behind either page. Non-empty search filters, ref filters, watch mode, and unbounded reads deliberately use the authoritative journal.
  • historyCount is the number of returned entries after filters.
  • Entries are sorted by occurredAt, then eventId, as display chronology only. Writers may have skewed clocks, and an event received later can therefore backfill an earlier visible position; this order is neither append order nor causal precedence.
  • --revision, --track, and repeated --event-type narrow the returned entries.
  • --ref <name> filters to events of revisions associated with a ref (a short branch name is normalized to its full ref). --by chooses how --ref matches: label (the recorded label, offline; the default) or liveness (reachability from the ref's live tip).
  • --filter <query> runs the review filter grammar over the same per-event search records the inspector's timeline queries. Event-surface qualifiers: type: (label or wire id; a comma list ORs values, e.g. type:observation,assessment), track:, actor: (the actor: id prefix is optional), revision:, snapshot:, check: (passed|failed|errored|skipped), assessment:, is: (open|answered), tag: (a full tag string or its first-colon key — tag:issue:191 or tag:issue), and before:/after: (ISO-8601 date/datetime prefixes). Bare terms match free text — including body content even without --include-body — and a leading - negates a clause. The filter applies before --limit/--cursor windowing and composes with all the typed flags above. A known-but-unsupported qualifier or value (for example attention: here) exits non-zero with the diagnostic; the deprecated status: alias for check: still runs behind a stderr hint.
  • --limit <n> returns at most N entries as a forward page (from the start, or from --cursor); the response carries a nextCursor to continue. --cursor <cursor> continues from a previous response's opaque nextCursor. Omit both for the full history.
  • --watch re-renders whenever the store's liveness changes, polling client-side at --poll-ms (default 3000). It is pull-only — no daemon and no filesystem watch — and is cancelled with Ctrl-C; under --watch the same --limit page is re-rendered on each liveness change.
  • Succession and commit/ref association filters include revision-captured, revision-commit-associated, revision-commit-withdrawn, revision-ref-associated, and revision-ref-withdrawn.
  • Body-like text is omitted by default. --include-body hydrates observation bodies, input request bodies, input request response reasons, assessment summaries, validation summaries, and imported-note bodies. Native Markdown/plain content-type fields are included for those body-like event fields when they are not plain text.
  • Duplicate semantic events remain visible as separate entries while shared duplicate diagnostics are included in the document.

Verification status and endorsement readback

pointbreak history, pointbreak revision show, and the inspector endpoints render two reader-relative, advisory facts beside each event. They render only — they never gate a write or change an exit code, and the temporal require-verified-endorsement tier is out of scope.

  • verificationStatus ∈ valid | invalid | untrusted_key | unsigned — the per-event signature ladder, resolved against the reader's .pointbreak/allowed-signers.json. An event signed by a key the reader has not enrolled reads untrusted_key; an event with no signature reads unsigned.
  • endorsements[] — for an endorsed (co-signed) target event, one entry per endorsement attestation (co-signature member). Because signatures are deterministic, one signer yields one attestation per target, so this is normally one entry per endorsing signer; an actor who endorses the same target with more than one enrolled key surfaces one entry per key (each is a distinct attestation, not collapsed):
    • classification ∈ endorsement-trusted | unknown_endorser | ambiguous_endorser.
    • endorser — the resolved actor, present only when endorsement-trusted.
    • endorserAttributes — the endorser's attested kind/roles from .pointbreak/actor-attributes.json. This is a sibling enrichment rendered beside the classification; it is not an input to how the classification is decided.

Both are reader-relative: the same endorsement carrier may read endorsement-trusted for a reader who has enrolled the endorser and unknown_endorser for a reader who has not. A field is omitted when empty — no verification policy configured, no endorsement on the target, or no attested attributes for the endorser. The classification rules are decided in ADR-0013.

{
  "eventId": "evt:sha256:…",
  "eventType": "work_object_proposed",
  "verificationStatus": "unsigned",
  "endorsements": [
    {
      "classification": "endorsement-trusted",
      "endorser": "actor:git-email:kevin@swiber.dev",
      "endorserAttributes": { "kind": "human", "roles": ["reviewer"] }
    },
    { "classification": "unknown_endorser" }
  ]
}

History is not the full revision row projection. Use pointbreak revision show for the composite narrative-first plus snapshot-complete view of one captured revision.

pointbreak revision list

This is the legacy flat Revision directory. It remains useful for exact historical discovery, but its proposal-supersession classification is not Change current-set authority. Use pointbreak change list and pointbreak change show for stable work and contextual topology.

pointbreak revision list [--repo <path>] [--object <object-id>] [--ref <name> [--by label|liveness]] \
  [--filter <query>] [--integration-ref <name>] [--worktree <path>] [--all | --unreachable] \
  [--limit <1..500> [--cursor <cursor>]] [--format <fmt>]

pointbreak revision list is the discovery surface for captured revisions. It emits pointbreak.review-revision-list JSON with eventCount, revisionCount, entries, and the serving lane's identity (eventSetHash or projectionStamp) sorted by capture time. Each entry carries the revision id, the content-only object id, the capture endpoints when Git provenance exists, the optional capture summary, and objectArtifactContentHash. Provenance-free revisions remain first-class entries and omit source, base, and target together rather than inventing Git coordinates. Text output places the summary beside the short revision id and labels provenance-free entries explicitly; Inspector and VS Code use the summary as the primary selection label.

  • --limit <n> opts into newest-first, one-captured-revision-per-row paging and accepts values from 1 through 500. nextCursor is present when another page remains; pass it back with the same options via --cursor. A cursor binds the serving profile and snapshot. If either changes, the command exits with revision page changed; retry without --cursor instead of translating or silently restarting it. Text output reports the displayed rows separately from the total and prints a continuation cue when another page remains.

  • A flagless bounded page uses a current active derived generation and carries projectionStamp. Object, ref, review-filter, reachability, integration-ref, and worktree-scoped pages retain the authoritative implementation and carry eventSetHash. If an active generation is unavailable, a first page falls back authoritatively with one build hint; its returned cursor is therefore authoritative too.

  • --object <object-id> lists only the revisions that share one content object. Coincident content may span supersession threads, so this is a listing/grouping lens, never a head selector.

  • --ref <name> filters to revisions associated with a ref (a short branch name is normalized to its full ref). --by chooses how --ref matches: label (the recorded label, offline; the default) or liveness (reachability from the ref's live tip). The succession view (the supersession DAG and a thread's competing heads) is reported by this same projection; there is no separate lineage surface.

  • --filter <query> runs the same review filter grammar on the revision surface, over per-revision records aggregated from each revision's review facts. Revision-surface qualifiers: track: and actor: (the union across the revision's facts; the actor: id prefix is optional), revision:, snapshot:, assessment: (the resolved current assessment), is: (open|answered|unassessed|stale|follow-up|contested|superseded), tag: (full string or first-colon key), attention: (open-request|unassessed|validation-context|follow-up|stale-fact), and before:/after: (ISO-8601 prefixes over the capture time); bare terms match the revision's human text, and a leading - negates a clause. is:superseded and is:contested read replacement from the same authority as attention list: on a store that holds Change claims a revision is superseded only when every Change that holds it has replaced it, and nothing is contested (divergence inside a Change surfaces through change show); proposal-borne supersedes decides them only on a store with no Change claims. Only a filtered listing builds the per-revision overviews and supersession classification — a plain listing pays no new cost — and a grouped row filters on its representative revision. A known-but-unsupported qualifier (type:/check: on this surface) exits non-zero with the diagnostic; the deprecated status: alias for assessment: still runs behind a stderr hint.

  • --integration-ref <name> sets the reachability target for the merged status: a revision is merged only when it is an ancestor of this ref (equality counts). It defaults to the repository's detected default branch (origin/HEAD, else local main/master) — the same narrow default pointbreak revision show applies — so the status answers "did this land on the default branch?". When no default branch is detected it falls back to broad reachability (any live tip).

  • --worktree <path> scopes the listing to captures belonging to the worktree at that path.

  • Every recorded revision is shown by default, including revisions whose anchored commits are all unreachable. --all remains an accepted compatibility spelling of that default; --unreachable explicitly narrows the listing to only those unreachable revisions (--orphans is a deprecated alias).

  • Each entry carries mergeStatus: merged (an ancestor of the integration target), open (still reachable from a live ref without having landed there), unreachable (no live ref reaches any anchored commit — present-but-unreachable and gc'd objects alike; per-commit detail stays on revision show), or unknown (floating capture, divergent landing claims, or an unavailable repository). The former orphaned status is retired.

pointbreak revision show

This is the legacy composite Revision view. Use pointbreak change revision <change-id> <revision-id> --artifact-hash <sha256> for an exact Change-capable resource and pointbreak change show <change-id> for current-set selection.

pointbreak revision show [REVISION] [--repo <path>] [--track <track-id>] \
  [--include-body] [--format <fmt>]

pointbreak revision show is the composite view for one revision. It emits compact pointbreak.review-revision v2 JSON by default.

  • When exactly one revision has been captured, Pointbreak selects it automatically.
  • If multiple revisions exist, pass the [REVISION] positional. It is a head seed: a current head resolves exactly; a superseded revision resolves its thread's current head; and a thread with competing heads is reported as competing rather than auto-picked.
  • revision show retains legacy proposal-supersession selection and facets and does not follow Change replacement: the [REVISION] head seed, validationChecks[].supersededByRevisions, and stale_by_superseding_revision read the proposal-borne supersedes list only, so a Revision a Change has replaced still resolves to itself. On a store that holds Change authority the document says so with the advisory diagnostic change_replacement_not_followed, and the text digest ends with the same pointer. Read Change-scoped replacement with pointbreak change show <change-id> (current set) and the exact Revision with pointbreak change revision <change-id> <revision-id> --artifact-hash <sha256>; change revision shares this projection without the redirect.
  • The output includes revision identity, event-set freshness metadata, filters, summary counts, current assessment status, native observations, input requests, assessments, validation checks, projection rows, and diagnostics.
  • Rows are narrative-first, then snapshot-complete.
  • commitRange.liveness is the read-time Git enrichment (best-effort; omitted when the repository cannot be read). perCommit[].condition is merged, live, unreachable (object present, no live ref reaches it), or missing (object gone) — availability and reachability stay distinguishable, and nothing is called orphaned. An unreachable commit also carries retention: reflog while a reflog entry still retains the object, none after expiry. refContinuity diagnoses each recorded ref association: current, advanced, rewritten (best-effort reflog evidence naming the rewriteAction, e.g. commit (amend), plus sameTree when both objects survive), moved (no rewrite evidence — expired reflog or a reset), deleted, or unknown. A rewritten ref adds a ref_rewritten diagnostic naming the recorded and current OIDs with the suggested explicit follow-up; reflog evidence never mutates the durable record.
  • --track <track-id> filters narrative facts without changing the selected revision, event-set freshness metadata, or captured snapshot completeness.
  • Body-like text is omitted by default. --include-body hydrates observation bodies, input request bodies and response reasons, assessment summaries, validation summaries, and imported-note bodies. Native Markdown/plain content-type fields are included for those body-like event fields when they are not plain text.
  • Each narrative member (observations, input requests and their responses, assessments, validation checks) and the revision identity (the capture event) carry the same reader-relative verificationStatus and endorsements (with endorserAttributes) readback documented under pointbreak history — advisory, render-only, resolved against the reader's .pointbreak/ trust and attributes config.

Revision-scoped selection seeds on the [REVISION] positional and resolves that revision's thread head; no implicit newest capture globally wins. Unscoped current selection with multiple unrelated captured revisions still errors at the selection boundary, but routine list, history, and exact-revision reads have no always-on ambiguous-current warning. A thread-level read may surface stale_by_superseding_revision for a revision that a newer revision supersedes. This release has no interdiff or stack DAG beyond the supersession graph.

Capture and succession facts stay signable under ADR-0004's generic EventToBeSigned contract with the Dead Simple Signing Envelope (DSSE) and pre-authentication encoding rules.

pointbreak revision show is distinct from pointbreak history: history is the chronological raw event listing, while pointbreak revision show is the composite revision view for agents and future frontends.