v3.0.0
Review Council evidence (epic IO-12475). Behavior change: in a
Harness-managed repository (one carrying .harness-cli/config.json) with a
harness login, a review now records itself on Harness by default — the run
header, consensus findings (which quote code), reviewer call statistics and
the JSON and Markdown reports as written. Hence the major version; every
report field is additive and pre-3.0 reports load unchanged.
src/telemetry/(RCL-37): a pure, allow-listedbuildRunEnvelope
wraps the report'srunheader with wire-shaped findings and calls, the
report'sstats, the SHA-256 digests of the exact bytes written to
--json-file/--markdown, and how the delivery came about.HarnessSink
posts the envelope, PUTs each declared artifact and posts converge events
under a 10 s timeout per request, sending the token only to the host that
minted it. AnOutboxat~/.rcl/outbox/<run id>/keeps what Harness could
not take and retries it — same run id,delivery: {mode: retried, spooled_at}— at the start of every command (five-second bound) or via
rcl telemetry flush; above 1 GB it stops spooling artifacts and reports the
affected runs as alossevent on the next successful flush.- Credentials. The stored
harness loginis the default;HARNESS_API_TOKENHARNESS_API_URLserve CI, and an environment token never pairs with the
stored host (half a pair is an error, not a fallback). A base URL carries no
user-info, query or fragment; a trailing slash is normalized away.
- Configuration.
harness.telemetry: off | envelope | findings | full
(defaultfull),--no-telemetry,RCL_TELEMETRY(off,0,false,
no, or a level name);
harness.parseFailuresopts in to a parse-failed call's raw answer (fenced
code and key-shaped strings removed, 32 KB cap) — by default only the parser
message travels. --evidence-requiredexits 4 when the evidence is incomplete — the
envelope was not acknowledged (spooled, refused, or the org has evidence
off), or a declared artifact was spooled or refused — and refuses a patch
file without--head-shaand a run with--no-telemetry,
RCL_TELEMETRY=offorharness.telemetry: off. Under--cithe gate's
exit code wins; the evidence failure is printed beside it. At the
envelopeandfindingslevels the declared artifact digests still
describe the reports rcl wrote — the server shows them as declared, not
received — and evidence is complete once the envelope is acknowledged.- Consent. The first delivery from a machine to a host prints a one-time
notice;~/.rcl/telemetry-noticerecords it. - Status line.
Evidence recorded: <url>·Evidence spooled (Harness unreachable); run rcl telemetry flush·Evidence not sent: <host> has not enabled review evidence for this organization. - Converge events.
converge-attemptemitsattempt_claimed(and
cap_changedunder--max-attempts),converge-reportemits
round_processed(andcap_changedunder--max-rounds) and persists the
round's run id in the run state,converge-verdictemits
verdicts_recordedandresolutionbound to that run id. rcl telemetry status | flush [--run <id>]for operators. Loss
reports go out in batches and are only removed once the server accounts
for every event; a refused batch is kept asloss/<id>.json.refused,
listed bystatus, never retried. A flush bounded by a deadline bounds
each request by what remains of it, and reports loss reports still
pending.- Transport hardening. Receipts larger than 64 KB are refused unread; a
WHATWG opaque redirect reads as a redirect; the credential's URL is
re-validated when the sink is built (https, orhttptolocalhost,
127.0.0.0/8,::1and*.localhost— the host comes from the login or
the environment, never from the repository). The consent notice precedes
the first transmission of any kind, converge events and flushes included. - Scrubbing. Every free-text field that leaves the process (errors,
warnings, runner claims, finding prose, consensus excerpts) is truncated and
scrubbed for bearer/key-shaped substrings. The reports written to
--json-file/--markdownare that same delivery view (aparse_failed
call keeps only the parser message unlessharness.parseFailuresis set),
so the uploaded artifacts are byte-identical to the files; with telemetry
off the raw report is written as before. - Transport. The Harness credential travels over TLS only, except to
loopback hosts (a local development server); a 401 keeps a spooled entry
for retry after re-login instead of failing it for good. - The rcl and rcl-converge skills document the evidence line, the
--evidence-requiredflush-retry rule (five minutes, then stop the loop),
and the opt-outs.
Phase 0 of the Review Council evidence ledger (RCL-36, epic IO-12475): the
report now says what it reviewed. The one network change: PR mode now
fetches the changed files through a compare pinned to the PR's base and head
object ids (GET /compare/{base}...{head}) for PRs up to GitHub's 300-file
compare cap, so the report's head_sha provably identifies the reviewed
patches even if the PR moves mid-fetch; larger PRs use the paged files
listing bracketed by PR reads and refuse to bind if the head or base moved.
- Self-describing
runheader on every report (ReviewResult.run):
client run id (UUIDv7), rcl version, command, target with exact
head_sha/base_sha/refs and adiff_sha256, roster with lanes
(blocking/secondary/async/verification), config digest with
thresholds and gating inline, spec and context-file digests, a best-effort
runnerclaim, timing,ci_exit_code(computed even without--ci), and
the converge context. The Markdown report gains a matching Reviewed line. - Exact-head binding.
PRMetadatagainsheadSha,baseShaand
mergeCommitShafrom the PR response GitHub already returns;--staged/
--working-treeresolveHEADand the merge-base with the remote default
branch;--head-sha/--base-shavouch for a patch file's commits;
--expect-head-shafails fast when the resolved head is not the expected
one — checked before the empty-diff exit, so a moved target never reads as a
clean round. --spec-source(flag|repo_file|harness_issue:<ID>) and
--converge-target/--round/--attempt(orRCL_CONVERGE_*) are
recorded in the header.- Identity on every finding.
ConsensusFinding.identitycarries the
convergestableFindingKeyat review time, on kept and below-threshold
findings alike. - Token usage on calls. Adapters record
usage
(inputTokens/outputTokens/reasoningTokens) where the SDK exposes
it — Anthropicusage, OpenAI and OpenRouterusage(with
completion_tokens_details.reasoning_tokens), GoogleusageMetadata—
including on truncated or refused answers; chunked reviews sum it. - Pre-3.0 reports (no
run, noidentity) load unchanged in
converge-report,discuss, andmodels seed.
npm: https://www.npmjs.com/package/review-council/v/3.0.0
Tarball SHA-256: fc87079625e9bd6d83482a06b21881680a033d8aff70fd665e7d4fbabf4b09aa