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

FieldTypeRequiredDescriptionConstraints
verdictenumyesconfirmed: 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.
  • one of "confirmed", "needs_validation", "rejected"
fingerprintstringyesThe stable id: repository-relative file + whitespace-normalised, lowercased finding text (for example `server/x.js:the cache never expires`).
  • minLength 1
  • maxLength 200
titlestringyes
  • minLength 1
  • maxLength 200
descriptionstringyesWhat is wrong, in plain words; no severity claim beyond the evidence.
  • minLength 1
  • maxLength 4000
tracehttps://openvibe.network/contracts/agent/finding.v1.json#/$defs/locationyesWhere the issue lives, repository-relative, most specific first.
  • minItems 1
  • maxItems 50
evidencehttps://openvibe.network/contracts/agent/finding.v1.json#/$defs/evidenceyesWhat shows the fact: the source read, the command and its output, the response, the screenshot or the test.
  • minItems 1
  • maxItems 50
severityhttps://openvibe.network/contracts/agent/finding.v1.json#/$defs/severity
confidencehttps://openvibe.network/contracts/agent/finding.v1.json#/$defs/confidence
remediationhttps://openvibe.network/contracts/agent/finding.v1.json#/$defs/remediation
claimed_root_causestringThe suspected cause of a needs_validation lead, stated as a claim to test.
  • minLength 1
  • maxLength 2000
blockersarray of stringThe exact reason the claim could not be proven here (a credential, an environment, data, a downstream service).
  • minItems 1
  • maxItems 20
  • items: minLength 1
  • items: maxLength 500
validation_planhttps://openvibe.network/contracts/agent/finding.v1.json#/$defs/validation_plan
reasonstringWhy a rejected claim does not stand.
  • minLength 1
  • maxLength 2000

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 }] }