# Feedback Contract

Date: 2026-06-01 (current-state note updated 2026-07-14)

Status: local feedback candidate, draft, verification, Markdown, and issue-URL
generation are shipped. These commands do not mutate GitHub, and public output
fails closed unless the run verifies as `share_ready`.

## Purpose

Feedback is the bridge between simulation evidence and public issue filing.

`humanish feedback` should let a persona simulation say:

```text
this user-like run found this concrete friction
here is the evidence
here is the likely owner
here is the redaction proof
here is the next state
```

It should not be an issue spammer, infra dependency, or generic comment
collector.

## Privacy Rule

Feedback payloads must be public-safe by default. They may not contain PII,
PHI, secrets, keys, tokens, raw private transcripts, private screenshots, raw
customer data, raw patient data, or private product source.

Public issue drafting fails closed if redaction cannot prove the payload is
safe. A verified run bundle is not automatically public-promotable: feedback
commands also require `humanish verify` to report
`shareSafety.status: share_ready`.

For an otherwise valid run whose only sharing restriction is raw screenshots,
`humanish export --run RUN --format bundle --redact-screenshots --out ./shared-study`
produces a separate, reverified workspace. Feedback commands use
`--cwd ./shared-study --run RUN`; the source retains its original local-only grade
and readable frames. Exported thumbnails do not replace local visual adjudication.

## Command Stages

```bash
humanish feedback list --run latest
humanish feedback draft --run latest --json
humanish feedback verify --run latest --json
humanish feedback issue --run latest --repo owner/repo --format markdown
humanish feedback issue-url --run latest --repo owner/repo
```

### `list`

Reads feedback candidates from the run bundle. Does not mutate. Candidates are
generated by lab/adapters when actor evidence identifies a concrete
setup-quality gap, ceremonial/absent study quality, target-app blocker, or
Humanish CLI blocker. The OSS
meta-lab is one maintainer dogfood example, not the only candidate source.

The list also shows any saved draft. An empty `candidates` array means no usable
candidate was recorded; it does not mean a run-summary draft is unavailable.
Listing does not create a draft or check public-sharing eligibility.

For completed computer-use sessions, participant-reported friction comes from
the redacted closing report and observed-report clauses in earlier messages.
Matching `stopWhen` or ending a dwell window does not discard an earlier
report or change the successful completion verdict. Exact repeated reports
appear once in the lane's candidate. Harness notices, reasoning, and observed
page content do not become participant findings; quoted app copy and negated
reports retain the existing exclusions. Code excerpts are treated as quoted
material. Interim matching requires an observation-shaped clause and filters
common plans, questions, and hypotheticals; a report followed by a retry plan
can still qualify. This text
heuristic does not establish that a reported defect is real or independently
confirmed. A custom session's closing `reason` remains eligible even when it
was not repeated in the message trace.

### `draft`

Builds structured feedback from the first usable run candidate, or the candidate
selected with `--candidate`. With no candidate, a dry run produces a contract
follow-up and a live run produces a summary of its recorded review. These
fallbacks do not add a finding to the candidate list. All drafts require a
verified `share_ready` run and are written under the run bundle, not GitHub.

### `verify`

Checks schema, evidence pointers, idempotency key, redaction result, and public
issue eligibility.

### `issue`

Prints or writes a public-safe GitHub issue body. It does not call the GitHub
API. The user files the issue in the public or eventually public repository.

### `issue-url`

Prints a prefilled GitHub issue URL when the platform supports one. It still
does not create the issue.

## Schema

```yaml
humanish_feedback:
  schema: humanish.feedback.v1
  run_id: "<run-id>"
  adapter_id: "<adapter-id>"
  scenario_id: "<scenario-id>"
  persona_id: "<persona-id-or-class>"
  actor: "<actor-runtime>"
  substrate: "<substrate>"
  failure_owner: "harness|target-app|actor|environment|unknown"
  summary: "<public-safe concrete summary>"
  expected: "<public-safe expected behavior>"
  actual: "<public-safe observed behavior>"
  source_bundle: "<path-or-url>"
  evidence:
    - path: "<relative artifact pointer>"
      kind: "screenshot|state|review|trace|log|filesystem"
      note: "<public-safe note>"
  redaction:
    status: "passed|failed|not_applicable"
    notes: "<public-safe note>"
  idempotency_key: "<stable-key>"
  proposed_next_state: "watch|adapter-hardening|target-app-setup|actor-auth|setup-quality-review|study-quality-review"
  acceptance_proof:
    - "<command or artifact that would close this>"
  adapter:
    namespace: "<adapter namespace>"
    data: {}
```

`adapter` is optional and namespaced. Adapters may place product-specific
concepts there (for example route groups, milestone ids, product acceptance
details, or adopter-owned rubric data). Core validates only that `namespace` is
non-empty and `data` is a record; keys inside `data` are never core enums.

## Failure Owners

| Owner | Meaning |
| --- | --- |
| `harness` | Humanish or adapter logic produced invalid evidence or execution. |
| `target-app` | The target app setup, dev server, or local surface blocked the run. |
| `actor` | The coding-agent/persona actor failed to complete a requested setup or usage path. |
| `environment` | E2B, local browser, shell, filesystem, network, or dependency substrate failed. |
| `unknown` | Evidence is useful but ownership is not yet clear. |

## Issue Draft Gates

Generating a public issue draft is blocked when:

- required schema fields are missing;
- source bundle is missing;
- evidence pointers are missing or invalid;
- redaction did not pass;
- `shareSafety.status` is `local_only` or `blocked`;
- any payload may contain PII, PHI, secrets, or private operational context;
- proposed next state is `agent_ready` without a readiness block;
- the feedback is a dry-run-only product claim;
- idempotency key is missing.

## GitHub Issue Semantics

Generated acceptance commands use the installed `humanish` CLI from the workspace
containing the evidence. They require no repository package script or manifest.
When regenerating feedback from a retained first-party candidate, exact legacy
`pnpm humanish -- verify/watch` templates for the same run are projected to direct
CLI commands. Recognition checks the existing candidate/stream identity and
idempotency conventions; it is a compatibility rule, not provenance attestation.
Custom candidates and instructions remain unchanged. Source bundles, candidates
and receipts are never rewritten by this projection.

GitHub issues filed from feedback should say `contributes to` unless the
acceptance proof closes the full product claim. The public issue should include
only redacted evidence pointers and reproduction instructions that a maintainer
can use without private local context.

The public CLI should not require GitHub tokens, hosted product memory, queues,
webhooks, Actions, databases, or Projects. Maintainers may later build separate
repo-local tooling that consumes the same issue schema, but that is outside the
default public feedback path.
