AgentFinding agent.finding@1
Generated at from
openvibe-contracts v0.419.0 and
openvibe-sdk v0.161.0.
- Version
- 1.0.0
- Owner
- actor
- Visibility
- public
- Status
- active
- Compatibility
- backward
- Schema
https://openvibe.network/contracts/agent/finding.v1.json
One finding of a review, a hunt or a security pass. The verdict is the evidence bar, not the severity: `confirmed` means the finding was reproduced or re-read and carries `severity` and `confidence`; `needs_validation` is an unprovable claim turned into a lead with an exact `blockers` entry and a `validation_plan`, and it has no severity by design (never noise, never a silent pass); `rejected` says why it does not stand. `fingerprint` is the stable identity — repository-relative file plus whitespace-normalised, lowercased text — so a re-wrapped finding keeps its id while a real rewording becomes a new one. `trace` and `evidence` carry repository-relative locations and the commands or answers that show the fact. A validator must also refuse `severity.overall_severity` above the demonstrated `severity.impact`; the schema cannot rank two enums, so `description` states the rule.
Fields
| Field | Type | Required | Description | Constraints |
|---|---|---|---|---|
verdict | enum | yes | confirmed: reproduced or re-read by a second agent. needs_validation: a lead that could not be proven locally; it carries blockers and a plan, never a severity. rejected: the claim was refuted; it carries a reason. |
|
fingerprint | string | yes | The stable id: repository-relative file + whitespace-normalised, lowercased finding text (for example `server/x.js:the cache never expires`). |
|
title | string | yes |
| |
description | string | yes | What is wrong, in plain words; no severity claim beyond the evidence. |
|
trace | https://openvibe.network/contracts/agent/finding.v1.json#/$defs/location | yes | Where the issue lives, repository-relative, most specific first. |
|
evidence | https://openvibe.network/contracts/agent/finding.v1.json#/$defs/evidence | yes | What shows the fact: the source read, the command and its output, the response, the screenshot or the test. |
|
severity | https://openvibe.network/contracts/agent/finding.v1.json#/$defs/severity | |||
confidence | https://openvibe.network/contracts/agent/finding.v1.json#/$defs/confidence | |||
remediation | https://openvibe.network/contracts/agent/finding.v1.json#/$defs/remediation | |||
claimed_root_cause | string | The suspected cause of a needs_validation lead, stated as a claim to test. |
| |
blockers | array of string | The exact reason the claim could not be proven here (a credential, an environment, data, a downstream service). |
| |
validation_plan | https://openvibe.network/contracts/agent/finding.v1.json#/$defs/validation_plan | |||
reason | string | Why a rejected claim does not stand. |
|
Examples
From the contract's own test fixtures: valid ones validate, rejected ones must fail.
Valid: confirmed
{
"verdict": "confirmed",
"fingerprint": "server/session.js:the cookie is set without httponly",
"title": "Session cookie has no HttpOnly flag",
"description": "The sign-in response sets ov_session without HttpOnly, so a script on the page can read it.",
"trace": [
{
"file": "server/session.js",
"line": 42,
"symbol": "setSessionCookie"
}
],
"evidence": [
{
"kind": "source",
"summary": "The cookie options omit httpOnly.",
"location": {
"file": "server/session.js",
"line": 42
}
},
{
"kind": "command",
"summary": "The sign-in response shows the cookie without HttpOnly.",
"command": "curl -si -X POST localhost:4900/signin -d '{}' | grep set-cookie",
"output": "set-cookie: ov_session=…; Path=/; SameSite=Lax"
}
],
"severity": {
"likelihood": "medium",
"impact": "high",
"overall_severity": "high"
},
"confidence": {
"level": "high",
"reason": "Reproduced against the local server and the source shows the same."
},
"remediation": {
"strategy": "Add HttpOnly to the cookie options.",
"code_changes": [
{
"file": "server/session.js",
"change": "Add httpOnly: true to the cookie options."
}
]
}
}Valid: needs-validation
{
"verdict": "needs_validation",
"fingerprint": "server/billing.js:the retry may debit twice",
"title": "A retried debit may charge twice",
"description": "The retry path calls the debit again without reading the receipt; on a real card this could charge twice.",
"trace": [
{
"file": "server/billing.js",
"line": 118,
"symbol": "debitRetry"
}
],
"evidence": [
{
"kind": "source",
"summary": "The retry calls debit() before the receipt is read.",
"location": {
"file": "server/billing.js",
"line": 118
}
}
],
"claimed_root_cause": "The retry does not look up the first attempt's idempotency key.",
"blockers": [
"A test charge needs the live payment provider's sandbox credential, which is not on this machine."
],
"validation_plan": {
"local": "Point the provider client at the sandbox and post one retried payment; the provider's ledger shows one or two charges.",
"deployment": "Replay a failed billing retry with a test account and read the provider's ledger."
},
"remediation": {
"strategy": "Reuse the first attempt's idempotency key on the retry."
}
}Valid: rejected
{
"verdict": "rejected",
"fingerprint": "server/cache.js:the cache never expires",
"title": "The cache never expires",
"description": "The review said the cache has no expiry; the entry it named has a TTL two lines down.",
"trace": [
{
"file": "server/cache.js",
"line": 31,
"symbol": "put"
}
],
"evidence": [
{
"kind": "source",
"summary": "The named call passes ttlMs.",
"location": {
"file": "server/cache.js",
"line": 31
}
}
],
"reason": "The TTL is set by the options object on line 34, which the review did not read."
}Rejected: confirmed-without-severity
{
"verdict": "confirmed",
"fingerprint": "server/x.js:a confirmed finding without severity",
"title": "A confirmed finding without a severity",
"description": "A confirmed finding must say how likely and how bad it is.",
"trace": [
{
"file": "server/x.js",
"line": 1
}
],
"evidence": [
{
"kind": "test",
"summary": "The failing test."
}
],
"confidence": {
"level": "high",
"reason": "The test fails."
}
}Rejected: lead-with-severity
{
"verdict": "needs_validation",
"fingerprint": "server/x.js:a lead with a severity",
"title": "A lead that still carries a severity",
"description": "A claim that could not be proven must stay a lead and carry no severity.",
"trace": [
{
"file": "server/x.js",
"line": 1
}
],
"evidence": [
{
"kind": "source",
"summary": "The source."
}
],
"claimed_root_cause": "A guess.",
"blockers": [
"No credential."
],
"validation_plan": {
"local": "Try it."
},
"severity": {
"likelihood": "low",
"impact": "low",
"overall_severity": "low"
}
}Rejected: lead-without-blocker
{
"verdict": "needs_validation",
"fingerprint": "server/x.js:a lead without its blocker",
"title": "A lead without a blocker",
"description": "An unprovable claim must say exactly what blocked it.",
"trace": [
{
"file": "server/x.js",
"line": 1
}
],
"evidence": [
{
"kind": "source",
"summary": "The source."
}
],
"claimed_root_cause": "A guess.",
"validation_plan": {
"local": "Try it."
}
}Rejected: rejected-without-reason
{
"verdict": "rejected",
"fingerprint": "server/x.js:a rejected claim without a reason",
"title": "A rejected claim without a reason",
"description": "A rejected finding must say why it does not stand.",
"trace": [
{
"file": "server/x.js",
"line": 1
}
],
"evidence": [
{
"kind": "source",
"summary": "The source."
}
]
}Validate
const contracts = require('openvibe-contracts');
contracts.validate('agent.finding@1', value); // { valid, errors: [{ path, message }] }