block / block/buzz

Proposal: optional verdict_ref on request_approval -- an independently-checkable claim alongside the approver's message

Open
#2,509 11 comments 0 reactions 0 assignees View on GitHub
Dominant language
Rust
Stars
32.7k
Forks
4.3k
Avg merge
1d 13h
Merged PRs (30d)
253

Description

## Summary

Not competing with #2376/WF-08 -- that's the plumbing (suspend/resume/grant/deny) and it's real, needed, orthogonal work. This is a separate, additive proposal for what the approver *sees* while deciding, once that plumbing lands.

`request_approval` suspends a run and waits for a human (or pubkey) to grant/deny via `from`. That's identity-gated authorization -- is this party allowed to say yes. It doesn't yet give the approver anything about whether the specific action is *sound*: the `message` field is free text, not a checkable claim.

Proposing an optional field that attaches an independently-checkable pre-action claim to the approval request as input to the human decision, never a replacement for it.

## Concrete shape

Extend `request_approval`'s config with an optional `verdict_ref`:

```
action: request_approval
from: "@release-manager"
message: "Deploy prod config v3"
verdict_ref: "sha256:1a3a2675...c02" # optional -- content-addressed pointer to an external, independently-checkable claim
timeout: 24h
```

When present, the `workflow_approvals` row carries `verdict_ref` alongside the token hash, and the kind:46010 announcement includes it so it shows up in the approver's needs-action feed next to the message -- something concrete to check, not just prose to trust. The approver still grants or denies; the claim is context. Additive on the request + announcement event only -- no changes to the grant/deny relay handlers or the resume path, so it doesn't depend on WF-08 landing first and could ship in parallel.

## Why content-addressed, not inline

A pointer (vs. embedding the claim's payload) means the approver isn't asked to trust whoever attached it -- they (or anyone auditing the thread later) independently recompute/verify the referenced claim against its own issuer's public key, the same non-repudiation property buzz's signed-event model already has everywhere else. The field shape doesn't need to name any specific issuer -- any signed, recomputable claim fits the slot. We run one shape of this (a pre-action verdict, checkable without an account) and would build a real worked example once WF-08 lands, but that's one implementation, not what the field itself commits to.

## Scope

Purely additive. Doesn't block or get blocked by #2376. `from` stays authoritative on who can grant -- this changes what they see, not who decides.

## Worked interop appendix (added after cross-verification with @ThoughtProof)

Two independently-implemented, independently-recomputed digest pairs — useful for anyone implementing a `verdict_ref`-compatible checker who wants a literal fixture to test their own canonicalization against, rather than trusting either party's claim:

**Pair 1 — bare content hash (no envelope):** `artifact_hash` (ThoughtProof's side) and `action_digest` (ours) over the same raw bytes matched directly, no canonicalization involved.

**Pair 2 — envelope layer, deliberately non-interchangeable:** `decision_ref` (ours, binds content hash + policy fields + verdict) and `package_digest` (ThoughtProof's, binds the verify *request* only — claim/evidence/mode, no outcome enum) sit at the same structural layer but commit to different objects by design. Don't expect them to be equal even when the underlying `artifact_hash` matches.

Fixture (experiment-only, not a production contract):
```json
{"claim":"","evidence":"","mode":"handoff","tier":"standard"}
```
Canonical form (RFC 8785 / JCS, undefined keys stripped):
```
{"claim":"","evidence":"","mode":"handoff","tier":"standard"}
sha256: d735f0020908d304d5b331665544f3cd85b20df64f2d1639d4251d4bf3aa5788
```
Verified independently on both sides against the same literal fixture: our path (`json.dumps(obj, sort_keys=True, separators=(",", ":"), ensure_ascii=False)`) and ThoughtProof's (`canonicalize`, RFC 8785 proper) — no shared code, matching output. A mismatch on this exact fixture in practice is almost always key-stripping or float-formatting drift, not a real digest-scheme disagreement.

Contributor guide

Open the contributing guide

Research direction

Start by locating the request_approval configuration, the workflow_approvals row, and the kind:46010 announcement path described in the proposal. Determine how an optional verdict_ref would be carried through the request and announcement while leaving grant/deny relay handlers and the resume path unchanged; done means the reference is available to approvers without replacing human authorization.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
authorization, backend
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.