zephyr-edge-contract
Version:
Edge contract for Zephyr
173 lines (145 loc) • 10.8 kB
Markdown
# Change Attribution
Use when enabling optional human/AI attribution or comparing versions built from
uncommitted source. The Zephyr Attribution integration uses Git AI; a skill alone
cannot reliably observe file writes.
## Enable with consent
The `with-zephyr` CLI offers **Enable Change Attribution** after SDK setup in an
interactive terminal. It links to [Git AI installation](https://usegitai.com/docs/get-started)
and separately offers **Install Agent Integrations**. Non-interactive invocation
does not opt in; `--dry-run` and `--no-attribution` do not create configuration.
Explicit non-interactive setup:
```bash
pnpm dlx with-zephyr . --attribution --attribution-agents codex claude grok
```
Storage defaults to **local**. The interactive offer also asks local versus
remote; `--attribution-storage remote` selects remote explicitly. Read
[repository storage and policy](attribution-storage.md) before enabling remote:
free accounts include patches/changed-line text; paid/BYOC defaults omit them.
This writes repository-root `.zephyr/attribution.json` and merges hooks into
`.codex/hooks.json`, `.claude/settings.json`, and/or `.grok/hooks/zephyr-attribution.json`. Codex/Grok also install `.zephyr/attribution-hook.cjs` for metadata. It preserves existing hooks
and settings, validates documents before writing, and does not modify global
settings or grant hook trust. Review the Codex project hooks with `/hooks` and
restart agent sessions. Grok requires its native project trust review (`/hooks-trust`); this grants folder trust for its other project integrations too. T3 uses the same Grok integration through ACP. Install the Git AI binary separately through its linked
instructions; the codemod does not run a downloaded installer. Skip the agents
flag for source capture only, or when existing Git AI hooks already cover the
agents. The installer may also configure agent hooks globally; avoid duplicating
the same integration at global and project scope.
Known human evidence needs a Git AI editor integration, available through the
same setup link. Agent hooks alone do not establish which remaining edits were
human. Missing evidence always remains **unknown**.
## Source records and comparisons
An opted-in SDK captures repository-wide Git-eligible working-tree files,
including unstaged and untracked files, rather than substituting HEAD or the
index. A deterministic fingerprint covers paths, file modes, and content hashes.
Private immutable source copies and version-to-source receipts stay under the
worktree's Git directory, in `zephyr-attribution/`. They are never build assets.
Comparisons require those local copies; a fresh clone cannot retrieve them from
Zephyr or Git AI notes. They are not synchronized or pruned automatically.
Install `zephyr-cli` to inspect the records without login or deployment:
```bash
pnpm exec ze-cli attribution status
pnpm exec ze-cli attribution capture --format json
# Use the two sourceId values returned by capture, or local Zephyr snapshot IDs.
pnpm exec ze-cli attribution compare <before> <after> --format json
```
Use `-C <project>` to select another project. Differences report additions,
removals, binary changes, and file modes. Attribution on a removed line describes
its original contributor; it does not identify who deleted it. Reverted edits
disappear from the net source difference.
Local mode attaches no attribution to uploaded snapshots or build stats. Remote
mode sends full evidence to a dedicated private endpoint and includes a small
acknowledged record reference in snapshot/build-stat `changeAttribution`. The
authenticated snapshot `creator` remains the deployer; contributor identities
are self-reported Git AI evidence, not verified people. Server endpoint/policy
persistence and a dashboard version-difference UI require control-plane support
and are not implemented in this SDK workspace.
## Harness, prompt initiator, effort, and usage
`workspaceHuman` identifies the Git author associated with a capture. Hooks-off AI
changes can appear under this identity, but their edit origin remains unknown.
The Git author, prompting human, and authenticated snapshot creator are separate.
Set `ZE_ATTRIBUTION_INITIATOR` in each person's launcher environment to record the
prompt initiator, and `ZE_ATTRIBUTION_HARNESS` to identify a wrapper such as `t3`
versus `codex-cli`. For T3, configure these in the selected project/provider's
environment settings. These are self-reports, not verified account assertions;
do not put a shared person's identity into team-wide hooks. Missing values stay
absent. A skill cannot reliably prove which person typed a prompt.
Codex/Grok collect a private metadata ledger under the worktree Git directory.
Line origins join exact tool-call identities into `sessions`, keyed by agent,
native session, and turn. Model and effort changes retain the earlier turn's
metadata. Codex effort/provider/counters use a bounded optional rollout adapter
tested with CLI 0.160.0; rollout parsing is not a stable API. Grok model/effort
use its observed summary and usage files, tested with CLI 1.0.46 and T3 0.0.44.
Unsupported/missing metadata does not invent defaults. Grok uses Git AI's public
`agent-v1` interface; no fork is required for this bridge.
Grok 1.0.46 omits prompt IDs on tool events. The bridge brackets an active prompt
from `UserPromptSubmit` to `Stop`/cancellation and marks `turnAssociation` as
`active-prompt`, an inferred association. Native Codex turn IDs are marked
`native-turn-id`. Unassociated/background completions stay unknown. Concurrent
or background Grok work needs stronger native event linkage before claiming an
exact prompt association. Integration labels alone do not prove the harness.
Usage and cost belong to sessions, not individual lines. Session-cumulative
snapshots are **not additive**, including across model switches or versions.
The captured cost is either unavailable or harness-reported USD ticks with an
observation timestamp and partial flag. It is not inferred from token counts or
presented as an invoice. [xAI defines one USD as 10 billion USD ticks](https://docs.x.ai/developers/cost-tracking).
Hook-time Grok counters can lag a turn; only a native
finished-turn match refreshes them, otherwise they remain incomplete/partial.
Historical source receipts retain their observed metadata. Raw prompts,
responses, transcript paths, and arbitrary provider fields are not published.
## Coverage and correctness
- Git-ignored files, common build output (`dist`, `build`, `.next`, `.nuxt`,
`.output`), dependency/cache folders, `.env*`, `.npmrc`, `.netrc`, and private
key extensions are excluded. Add repository-relative prefixes to `exclude`
in the configuration. This is a scoped source record, not a complete build
reproduction or a general secret detector.
- Captures are limited to 20,000 files and 50 MiB. Submodules need exclusions.
Failures produce `unavailable` metadata rather than a partial source claim.
- Vite and `ze-cli <build>` observe source at build start and snapshot creation.
`boundary-match` means those two observations match; it does not prove no
transient edit occurred between observations. `changed-during-build` means
the records differ and neither should be presented as the exact consumed
inputs. Other engine adapters observe their generation start and publication;
prebuilt deployments observe upload preparation rather than the earlier compiler
invocation. Each generation uses at most one start and one publication copy.
- The Git AI working-log adapter supports `checkpoint/1.0.0` from Git AI 1.7.x,
tested with 1.7.5. It accepts attribution only when the checkpoint's content
hash matches the captured file. Stale checkpoints remain unknown. Committed
blame is deferred to files changed in local/remote comparisons, only for bytes
matching the captured commit. Captures retain working-checkpoint ranges and
mark matching committed bytes privately; unchanged files do not trigger blame
processes at build start. HEAD trees are read once and missing baseline blobs
in one batch. Comparison enrichment never rewrites the original receipts. Legacy untracked
`Human` checkpoints are not known-human evidence.
Since Git AI 1.7 JSON blame omits known humans, the adapter follows native Git
line origins into explicit `authorship/3.0.0` human attestations in local
`refs/notes/ai`. A commit's ordinary author is never sufficient evidence.
- `gitAiPath` can point to a compatible fork. Keep format changes behind the
adapter; don't infer authorship from file style or the absence of AI marks.
To disable capture, set `enabled` to `false`. Remove the installed Git AI and metadata command
entries from project hook documents to stop those hooks, retaining other hooks.
Existing local receipts remain available until explicitly deleted.
## Maintainer verification
`scripts/verify-change-attribution.mjs` builds an actual generated React/Vite app
three times with the local SDK. It uses the real Git AI binary and replays Codex
and editor hook fixtures, including a model field. It replaces the cloud transport
and checks same-commit source differences containing AI, known-human, and unknown
origins. Hook replays verify integration compatibility; they do not establish
that a real human typed the fixture or that a live Codex session used that model.
After building `create-zephyr-apps`, `with-zephyr`, `zephyr-agent`, `zephyr-cli`,
and `vite-plugin-zephyr` locally:
```bash
node libs/create-zephyr-apps/dist/index.js /tmp/zephyr-attribution-demo --template react-vite --package-manager pnpm --git --install --json
node libs/with-zephyr/dist/index.js /tmp/zephyr-attribution-demo --attribution --attribution-agents codex --git-ai-path /absolute/path/to/git-ai
node scripts/verify-change-attribution.mjs /tmp/zephyr-attribution-demo /absolute/path/to/git-ai
```
Use a disposable app: the verifier edits its template source and writes a private
`demo-report.json`. It needs Git AI's background service running. A replay failure
or missing evidence must fail verification, not be relabeled as human or AI.
For live trials, retain a source receipt after each real agent edit. The
`scripts/verify-live-attribution.mjs <generated-app> <manifest.json>` verifier
loads those private records, checks the expected model/effort/harness and actual
added line, compares versions sharing a commit, then builds the final app using
real Vite/SDK snapshot construction with cloud transport disabled. Manifest
cases specify `name`, `sourceId`, `file`, `text`, `kind`, and optional `model`,
`effort`, `harness`. These receipts are local observations, not cloud deployments.
Do not substitute hook replay for a requested live model/harness trial.