104907e311
Merge PR 87 Co-authored-by: Jason Walker <913443@dadeschools.net> Co-committed-by: Jason Walker <913443@dadeschools.net>
139 lines
5.0 KiB
Markdown
139 lines
5.0 KiB
Markdown
# LLM-Agent-SHA — Opaque Agent Attribution (Phase 0)
|
|
|
|
Convention for attributing work to a specific LLM session/workstream across
|
|
issues, branches, PRs, and review handoffs, without exposing a human or model
|
|
identity. Approved by the owner decision on issue #86
|
|
(`#issuecomment-1354`); this document implements **Phase 0 only**.
|
|
|
|
## The one rule that matters
|
|
|
|
`LLM-Agent-SHA` is **informational attribution metadata only**. It must never
|
|
be used for authentication, authorization, review eligibility, merge
|
|
eligibility, profile permissions, or any other security decision.
|
|
|
|
The security gates remain, unchanged:
|
|
|
|
- the **authenticated Gitea user** (self-review/self-merge protection),
|
|
- the **active MCP profile** and its `allowed_operations`
|
|
(see [`gitea-execution-profiles.md`](gitea-execution-profiles.md)),
|
|
- the fail-closed eligibility checks in `gitea_check_pr_eligibility`.
|
|
|
|
Two sessions with different `LLM-Agent-SHA` values that authenticate as the
|
|
same Gitea user are **the same actor** for review/merge safety. A different
|
|
SHA never unlocks self-review or self-merge. `tests/test_llm_agent_sha.py`
|
|
proves the eligibility logic never consults the SHA.
|
|
|
|
## Format
|
|
|
|
```text
|
|
LLM-Agent-SHA: llm-<12 lowercase hex chars>
|
|
```
|
|
|
|
Validation regex:
|
|
|
|
```text
|
|
^llm-[0-9a-f]{12}$
|
|
```
|
|
|
|
Examples: `llm-8f3a9c2d6b41`, `llm-41d0e7aa9f2c`, `llm-b7c93d441a08`.
|
|
|
|
### Generation
|
|
|
|
Generate 48 random bits, e.g. `python3 -c "import secrets; print('llm-' +
|
|
secrets.token_hex(6))"`, or hash a non-secret session UUID. An
|
|
operator-provided opaque ID is also fine.
|
|
|
|
Do **not** derive the value from any of:
|
|
|
|
- a Gitea token or other secret,
|
|
- an email address or username,
|
|
- a machine hostname or private filesystem path,
|
|
- a model or provider name,
|
|
- conversation contents.
|
|
|
|
The SHA must contain no model name, provider name, human name, email,
|
|
hostname, token, private path, or conversation-derived content. It is safe to
|
|
include in PR bodies, issue comments, and audit logs — and only there.
|
|
|
|
## Lifetime
|
|
|
|
Canonical lifetime is **per PR/workstream**: pick one SHA when starting an
|
|
issue and keep it through the branch, PR, and handoff for that workstream. A
|
|
per-session SHA is acceptable when the session maps cleanly to one
|
|
workstream. Do not reuse a SHA across unrelated workstreams.
|
|
|
|
## Placement
|
|
|
|
Phase 0 uses **visible markdown metadata blocks** (not hidden HTML
|
|
comments). Include the block in PR bodies and review handoffs; keep it out of
|
|
ordinary comments unless attribution is genuinely useful there.
|
|
|
|
**Never put the SHA in branch or worktree names.** Branches stay
|
|
issue-linked and human-readable (`docs/issue-86-llm-agent-sha-phase0`), per
|
|
the branch standard.
|
|
|
|
### Handoff metadata block (implementer → PR body / handoff report)
|
|
|
|
```markdown
|
|
LLM Handoff Metadata:
|
|
- LLM-Agent-SHA: llm-8f3a9c2d6b41
|
|
- LLM-Role: implementer
|
|
- Authenticated-Gitea-User: jcwalker3
|
|
- MCP-Profile: gitea-default
|
|
- Branch: docs/example-branch
|
|
- Worktree: branches/docs-example-branch
|
|
- Self-review allowed: no
|
|
```
|
|
|
|
### Review metadata block (reviewer → review comment)
|
|
|
|
```markdown
|
|
Review Metadata:
|
|
- LLM-Agent-SHA: llm-41d0e7aa9f2c
|
|
- LLM-Role: reviewer
|
|
- Authenticated-Gitea-User: sysadmin
|
|
- MCP-Profile: prgs-reviewer
|
|
- Eligibility: passed
|
|
```
|
|
|
|
## Same SHA vs same user vs same profile
|
|
|
|
Reviewers and operators must keep three distinct identities straight:
|
|
|
|
| Comparison | Meaning | Effect on eligibility |
|
|
|---|---|---|
|
|
| same `LLM-Agent-SHA` | same LLM session/workstream wrote both artifacts | **none — attribution only** |
|
|
| same authenticated Gitea user | same Gitea actor | **blocks** self-review / self-merge, regardless of SHA |
|
|
| same MCP profile | same capability set | governs `allowed_operations` (what actions are permitted at all) |
|
|
|
|
Concretely: an implementer session (`llm-8f3a…`, user `jcwalker3`) and a
|
|
would-be reviewer session (`llm-41d0…`, also user `jcwalker3`) have different
|
|
SHAs but the **same Gitea user** — the reviewer session is still the PR
|
|
author to Gitea and must not review, approve, or merge. Review handoffs
|
|
require a genuinely different authenticated user (e.g. `sysadmin` /
|
|
`prgs-reviewer`).
|
|
|
|
## Phase 0 scope (and what is deferred)
|
|
|
|
Phase 0 is documentation, handoff/review templates, and negative tests only.
|
|
Deferred to later owner-approved phases; none of this exists yet:
|
|
|
|
- launcher-enforced SHA generation,
|
|
- `LLM_AGENT_SHA` / `LLM_AGENT_ROLE` environment injection,
|
|
- `gitea_whoami` returning SHA/role,
|
|
- automatic PR body injection by MCP tools,
|
|
- audit schema changes requiring the SHA,
|
|
- release/orchestrator lineage tracking.
|
|
|
|
MCP tools neither read nor emit the SHA. Setting an `LLM_AGENT_SHA`
|
|
environment variable has no effect on any tool; the negative tests assert
|
|
eligibility results are byte-identical with and without it.
|
|
|
|
## Related documents
|
|
|
|
- [`llm-workflow-runbooks.md`](llm-workflow-runbooks.md) — the runbooks whose
|
|
handoffs carry these blocks
|
|
- [`gitea-execution-profiles.md`](gitea-execution-profiles.md) — profiles and
|
|
`allowed_operations` (the real permission gate)
|
|
- [`safety-model.md`](safety-model.md) — audit, redaction, confirmation gates
|