cora-results
A results file: what one or more runs scanned, how completely their engines covered each page, and what they found there. Each run of cora scan, and each of cora-mcp’s scans, writes one to runs/ in the state directory, so .cora/runs/<run-id>.json in a project by default, or where cora scan --out names. cora report merge combines several into one, and the report directory’s results.json holds the results cora scan or cora report merge compared with the baseline. cora baseline update accepts the violations of either.
Each version lists its fields, then a section for each object they hold, headed by its path, in which [] stands for each entry of a list. Where objects of several kinds share a path, each kind has a section, named by the field that tells them apart. A field marked required is in every object of its kind, and the description of any other says when it is absent.
Version 1
Section titled “Version 1”The version this release writes. Its JSON Schema is schemas/cora-results/v1.json in the @vispero/cora package and at https://cora.vispero.com/docs/0.10/schemas/cora-results/v1.json.
format(“cora-results”, required): The file’s format, alwayscora-results.version(1, required): The format’s version. A cora that meets a version newer than it reads fails withcontract.unsupported-version.fingerprintVersion(integer, required): The version of the algorithm that computed the findings’ fingerprints. A cora that computes an older version fails withcontract.unsupported-version, since it could match none of them.runs(array of objects, required): The runs the file holds, at least one, each once: the run that wrote it, or every run a merge combined.coverage(array of objects, required): What the runs scanned and how completely: apageentry for each target a run scanned or could not scan, and asourceentry for each set of rules a static engine applied to source files.findings(array of objects, required): What the runs found, each finding one rule’s violation, or result that needs a person’s review, on one element of a page or at one place in a source file. Each lies within what its run covered: its run’s coverage of its target or its file, by its engine, is notskippedand lists its rule.baseline(object): How the results compare with the project’s baseline: the accepted violations no finding matched, by whether the runs checked them. It is present only in compared results, such as the report directory’sresults.json, and absent from the file a run writes: https://cora.vispero.com/docs/ci/#the-report-directory
runs[]
Section titled “runs[]”id(string, required): The run’s ID: its start time in UTC to the millisecond, a hyphen and eight random lowercase letters or digits, such as20261005T221403123Z-k3j9x2ab. It is unique in the file, and names the file the run writes to the state directory, such as.cora/runs/20261005T221403123Z-k3j9x2ab.json.producer(string, required): What ran the run:cliforcora scan, andmcpfor cora-mcp’s scans. An open set: a cora that does not know a producer, such as one a newer cora writes, keeps and shows it as it is.coraVersion(string, required): The version of the package that ran the run, such as0.6.0:@vispero/coraforcora scan, and@vispero/cora-mcpfor cora-mcp’s scans.startedAt(string, required): When the run started, as an ISO 8601 time in UTC, such as2026-10-05T22:14:03.123Z.finishedAt(string, required): When the run finished, in the same form asstartedAt.engines(array of objects, required): The engines the run used, each once, with its version.browsers(array of objects, required): Each browser the run launched, once, with its version; empty when the run recorded none.rulesHash(string, required): A hash of the rules the run could run on any page, with each rule’s details such as its severity, as 32 lowercase hexadecimal characters. It counts every route’s rules, whatever pages the run scanned, so the shards of one run share it.configHash(string, required): A hash of the resolved config the run used, as 32 lowercase hexadecimal characters, over the keys that enter it, each with its default or the value a flag or an environment variable gave it. A run that narrows its rules, withcora scan --onlyor--skipor therulesof cora-mcp’s scans, records a hash of its own.cora report mergecounts shards as one run only when they share it. The config reference marks each key that enters the hash: https://cora.vispero.com/docs/reference/config/commit(object): The git commit the project was at as the run finished, and whether its working tree differed from it. Absent outside a git repository or when git could not read the commit, and for cora-mcp’s scans, which record none.shard(object): Which shard of a sharded run this is, ascora scan --shard 2/4sets it; absent for a run that was not sharded.
runs[].engines[]
Section titled “runs[].engines[]”id(string, required): The engine’s ID, such asaxe.version(string, required): The version of the engine’s library, such as axe-core’s4.14.0foraxe.
runs[].browsers[]
Section titled “runs[].browsers[]”name(string, required): The browser’s name, such aschrome, as the run’s targets record it in theirbrowser.version(string, required): The version the browser reported, which tells apart builds that share a name.
runs[].commit
Section titled “runs[].commit”sha(string, required): The commit’s full hash, as 40 lowercase hexadecimal characters, or 64 in a repository that uses SHA-256.dirty(boolean, required): Whether the working tree differed from the commit:truewhengit statuslisted any change, such as an edited or an untracked file.
runs[].shard
Section titled “runs[].shard”index(integer, required): The shard’s number, from 1 up tototal, such as2in--shard 2/4.total(integer, required): How many shards the run was split into, such as4in--shard 2/4.cora report mergefails withmerge.incomplete-shardsunless it has every one.
coverage[] where kind is “page”
Section titled “coverage[] where kind is “page””kind(“page”, required): What the coverage is of:pagefor one target in a browser,sourcefor source files a static engine checked.run(string, required): The ID of the run that recorded the coverage, one the file’srunslists.target(object, required): The page state the coverage is of, in its browser at its viewport.engines(array of objects, required): How each of the run’s engines covered the target, at least one, each engine once.unsettled(object): How cora gave up waiting for the page to settle: present only when the page was still changing as cora stopped waiting, and was scanned as it was then, so its findings can differ between runs: https://cora.vispero.com/docs/troubleshooting/#findings-that-differ-between-runs
coverage[] where kind is “source”
Section titled “coverage[] where kind is “source””kind(“source”, required): What the coverage is of:pagefor one target in a browser,sourcefor source files a static engine checked.run(string, required): The ID of the run that recorded the coverage, one the file’srunslists.engine(string, required): The static engine, one that checks source files rather than pages, and one the run lists.status(“complete”, “partial” or “skipped”, required): How much of its files the engine checked with these rules:completefor all of them,partialfor part of them, andskippedfor none of them, such as a file it could not parse.rules(array of strings, required): The rules the engine applied to these files, those that found nothing included. Each distinct set of rules it applied has an entry of its own, since a lint config can enable different rules for different files.files(array of strings, required): The files these rules ran on, or could not check, at least one, each from the repository’s root with forward slashes, such assrc/App.tsx.reasons(array of objects, required): Why the coverage is not complete: at least one reason when it ispartialorskipped, and none when it iscomplete.
coverage[].target
Section titled “coverage[].target”Also at: findings[].location.target
url(string, required): The page’s http or https URL: the one it settled on, or for a target not scanned the one requested, with credentials redacted. Its userinfo becomesREDACTED:REDACTED, and the value of a parameter that only ever carries a credential, such astokenorpassword, becomesREDACTED.keepsHost(boolean, required): Whether the target’s issues keep its host in their identity:falsefor a target the run’s base URL claims, one on its origin, its scheme, host and port, or one requested there that settled on the same page, as an upgrade tohttpsdoes, whose issues’ identity is its route key alone, so the app’s runs on a preview host and onlocalhostgive the same fingerprints;truefor any other target, a redirect’s landing on another page judged by its own URL, and for every target of a run without a base URL.browser(string, required): The name of the browser the page ran in, such aschrome. An open set: a cora that does not know a name, such as one a newer cora writes, keeps and compares it as it is.viewport(object, required): The size of the browser’s viewport the page was shown at.reachedBy(“navigation” or “interaction”, required): How the page state was reached:navigationfor the page as it loads,interactionfor a state that input after the load produced, such as a dialog a test opened.state(string): The name of a page state reached by interaction that its producer can reach again; absent for the page as it loads, and for a state no one can reach again on demand, such as one an agent reached.
coverage[].target.viewport
Section titled “coverage[].target.viewport”Also at: baseline.absent[].pages[].viewport
width(integer, required): Its width, in CSS pixels.height(integer, required): Its height, in CSS pixels.
coverage[].engines[]
Section titled “coverage[].engines[]”engine(string, required): The engine, such asaxe, one the run lists.status(“complete”, “partial” or “skipped”, required): How much of the target the engine scanned:completefor all of it,partialfor part of it, such as when the config’spage.excludeleft elements out or an iframe could not be scanned, andskippedfor none of it, such as when the page did not load.rules(array of strings, required): The rules the engine ran on the target, those that found nothing included.report(array of strings): Those ofrulesthe config’s rule selection set toreporton the target: their findings are listed, but never fail the gate and are never compared with a baseline. Absent when there are none.reasons(array of objects, required): Why the engine’s coverage is not complete: at least one reason when it ispartialorskipped, and none when it iscomplete.
coverage[].engines[].reasons[]
Section titled “coverage[].engines[].reasons[]”Also at: coverage[].reasons[]
code(string, required): Why, as a code, such asnavigation-failed. An open set: a cora shows a code it does not know, such as one a newer cora writes, as it is. The coverage reasons reference lists each code with what it means: https://cora.vispero.com/docs/reference/coverage-reasons/detail(string, required): What the reason holds, which depends on its code, as the code’s entry in the coverage reasons reference says, such asHTTP 404for a page that answered with that status.
coverage[].unsettled
Section titled “coverage[].unsettled”timeout(integer, required): The settle timeout that passed before the page settled, in milliseconds: the config’spage.settle.timeoutfor the page.
findings[]
Section titled “findings[]”rule(string, required): The rule, such asaxe/image-alt. The rules reference gives what each rule checks, and links its guidance: https://cora.vispero.com/docs/reference/rules/engine(string, required): The engine that found it, such asaxe, one its run lists.outcome(“violation” or “needs-review”, required): What the engine concluded:violationwhen the rule fails there, andneeds-reviewwhen it could not decide, such as for text over a background image, so a person must check. A finding that needs review never fails the gate and is never compared with a baseline.severity(“critical”, “serious”, “moderate” or “minor”, required): How much the issue hinders the people it affects, on axe-core’s impact scale: the engine’s own for this element when it gives one, as axe-core does, and otherwise its rule’s severity, which the rules reference lists. The gate fails on a new violation at or above the config’spolicy.failOn.wcag(array of strings, required): The WCAG success criteria the rule checks, such as1.4.3; empty for a best practice, which no success criterion requires.message(string, required): The rule’s one-line description, as the rules reference gives it, such asImages must have alternative textforaxe/image-alt.summary(string, required): What is wrong with this element, as the engine reports it, such as axe-core’s failure summary; empty when the engine gives none.fixClass(“mechanical”, “content”, “design” or “manual”, required): What fixing the issue takes: its rule’s fix class, which the rules reference describes: https://cora.vispero.com/docs/reference/rules/#fix-classesrun(string, required): The ID of the run that found it, one the file’srunslists, which gives its producer, its engines’ versions and its commit.location(object, required): Where the finding is: on an element of a page, for apagelocation, or at an opening tag in a source file, for asourcelocation, which a static engine reports.fingerprints(object, required): The fingerprints that identify the finding’s issue across runs. Findings with the same source fingerprint, or, for findings without one, the same element fingerprint, count as one issue.baselineState(“new” or “unchanged”): How the comparison with the project’s baseline counts the violation:newwhen the baseline does not accept it, andunchangedwhen it does. Present only in compared results, on each violation the gate counts; absent on a finding that needs review, on a violation of a rule set toreport, and on one in a page state no one can reach again, such as one an agent reached.
findings[].location where kind is “page”
Section titled “findings[].location where kind is “page””kind(“page”, required): Where the finding was found:pagefor an element of a page scanned in a browser,sourcefor an opening tag in a source file a static engine checked.target(object, required): The page state the finding was found on, in its browser at its viewport.element(object, required): The element the finding is on, and how to find it in the page.source(object): Where the finding is in the project’s source. Apagelocation holds it when the page was built with source stamps and the element, or an ancestor in its document, has a stamp that still matches its file; asourcelocation always holds it.
findings[].location where kind is “source”
Section titled “findings[].location where kind is “source””kind(“source”, required): Where the finding was found:pagefor an element of a page scanned in a browser,sourcefor an opening tag in a source file a static engine checked.source(object, required): Where the finding is in the project’s source. Apagelocation holds it when the page was built with source stamps and the element, or an ancestor in its document, has a stamp that still matches its file; asourcelocation always holds it.
findings[].location.element
Section titled “findings[].location.element”path(array of objects, required): The iframes and shadow roots the element is inside, outermost first; empty for an element in the page’s own document.selector(string, required): The element’s CSS selector, as the engine wrote it, in the document or shadow root the last hop leads into.html(string, required): The element’s markup, as the engine reported it.
findings[].location.element.path[]
Section titled “findings[].location.element.path[]”Also at: baseline.absent[].pages[].element.path[]
selector(string, required): The CSS selector of the iframe or the shadow host, in the document or shadow root the hop before leads into.into(“frame” or “shadow”, required): What the hop leads into:framefor the iframe’s document,shadowfor the host’s shadow root.
findings[].location.source
Section titled “findings[].location.source”file(string, required): The file, from the repository’s root, with forward slashes, such assrc/App.tsx.line(integer, required): The line the opening tag’s<is on, from 1.column(integer, required): The column of the opening tag’s<, from 1, counting UTF-16 code units, as ESLint and SARIF do: a tab is one column, and an emoji two.endLine(integer): The line the opening tag’s closing>is on, which may beline; absent when the location does not give its end.endColumn(integer): The column just after the opening tag’s closing>, counted ascolumnis; absent when the location does not give its end.openingTag(string, required): The opening tag as the source fingerprint hashes it: its source text from<to>, each run of whitespace written as one space.resolution(“element” or “call-site”, required): Whose opening tag the location is:elementfor the element’s own, when it has a source stamp of its own;call-sitefor its nearest stamped ancestor’s when it has none, such as an element a component fromnode_modulesrenders: the closest host element in the project’s source that encloses it.
findings[].fingerprints
Section titled “findings[].fingerprints”element(string): The element fingerprint: a hash of the rule, the page URL’s path, query and fragment, and the element’s path and selector, as 32 lowercase hexadecimal characters. Every finding on a page has one, and a finding in a source file none.source(string): The source fingerprint: a hash of the rule, the file and the opening tag, as 32 lowercase hexadecimal characters. A finding has one when its location holds asource, and none otherwise.
baseline
Section titled “baseline”absent(array of objects, required): The accepted violations the runs show fixed: each page entry cut down to the pages a run scanned completely with the entry’s rule and no longer found the violation on, and eachsourceentry whose file a run checked completely with its rule without finding it.cora baseline updatewith these results removes them.unverified(array of objects, required): The accepted violations the runs could not check, such as on a page they did not scan or scanned only in part: each page entry cut down to those pages, other than thosereportedlists, and eachsourceentry whose file no run checked completely with its rule.cora baseline updatekeeps them, unless the config no longer runs their rule there.reported(array of objects): The accepted violations of a rule the runs ran on their page only asreport, which neither shows them fixed nor leaves them unchecked: each page entry cut down to those pages.cora baseline updatekeeps them. Absent when there are none.
baseline.absent[] where kind is “page”
Section titled “baseline.absent[] where kind is “page””Also at: baseline.unverified[], baseline.reported[]
kind(“page”, required): What found the violation:pagefor a scan in a browser,sourcefor a static engine.rule(string, required): The rule the violation is of, such asaxe/image-alt.source(object): Where the violation is in the project’s source. Apageentry holds it when its violations were found with a source location, from source stamps, and itsresolutionsays whose opening tag that is. Asourceentry always holds it.pages(array of objects, required): Each page the violation was seen on, in a browser at a viewport, at least one.
baseline.absent[] where kind is “source”
Section titled “baseline.absent[] where kind is “source””Also at: baseline.unverified[], baseline.reported[]
kind(“source”, required): What found the violation:pagefor a scan in a browser,sourcefor a static engine.rule(string, required): The rule the violation is of, such asaxe/image-alt.source(object, required): Where the violation is in the project’s source. Apageentry holds it when its violations were found with a source location, from source stamps, and itsresolutionsays whose opening tag that is. Asourceentry always holds it.
baseline.absent[].source where resolution is “element”
Section titled “baseline.absent[].source where resolution is “element””resolution(“element”, required): Whose opening tag the source names.elementis the element’s own, when it has a source stamp of its own, and such an entry accepts the violation on every page the element appears on.call-siteis its nearest stamped ancestor’s, when it has none, such as for an element a component fromnode_modulesrenders, and such an entry accepts the violation only on the elements its pages record.fingerprint(string, required): The source fingerprint: a hash of the rule, the file and the opening tag, as 32 lowercase hexadecimal characters.file(string, required): The file, from the repository’s root, with forward slashes, such assrc/App.tsx.openingTag(string, required): The opening tag as the fingerprint hashes it: its source text from<to>, each run of whitespace written as one space.occurrences(integer, required): How many places in the file with this fingerprint the baseline accepts, at least one. One more such place makes them all new, since the baseline cannot tell which one was added. Acall-sitesource never holds it.
baseline.absent[].source where resolution is “call-site”
Section titled “baseline.absent[].source where resolution is “call-site””resolution(“call-site”, required): Whose opening tag the source names.elementis the element’s own, when it has a source stamp of its own, and such an entry accepts the violation on every page the element appears on.call-siteis its nearest stamped ancestor’s, when it has none, such as for an element a component fromnode_modulesrenders, and such an entry accepts the violation only on the elements its pages record.fingerprint(string, required): The source fingerprint: a hash of the rule, the file and the opening tag, as 32 lowercase hexadecimal characters.file(string, required): The file, from the repository’s root, with forward slashes, such assrc/App.tsx.openingTag(string, required): The opening tag as the fingerprint hashes it: its source text from<to>, each run of whitespace written as one space.occurrences(not allowed): How many places in the file with this fingerprint the baseline accepts, at least one. One more such place makes them all new, since the baseline cannot tell which one was added. Acall-sitesource never holds it.
baseline.absent[].source where baseline.absent[].kind is “source”
Section titled “baseline.absent[].source where baseline.absent[].kind is “source””fingerprint(string, required): The source fingerprint: a hash of the rule, the file and the opening tag, as 32 lowercase hexadecimal characters.file(string, required): The file, from the repository’s root, with forward slashes, such assrc/App.tsx.openingTag(string, required): The opening tag as the fingerprint hashes it: its source text from<to>, each run of whitespace written as one space.occurrences(integer, required): How many places in the file with this fingerprint the baseline accepts, at least one. One more such place makes them all new, since the baseline cannot tell which one was added. Acall-sitesource never holds it.
baseline.absent[].pages[]
Section titled “baseline.absent[].pages[]”host(string): The page’s host, its hostname and any port its URL names, such asexample.comorlocalhost:5173, where the issue’s identity keeps it: a page outside its run’s base URL, and every page of a run without one. Absent for a page the base URL claims.route(string, required): The page’s route key: its URL’s path, query and fragment, without the scheme, host or port, so under the base URL the app’s preview host and production share it, such as/pricing?plan=team.browser(string, required): The name of the browser the page ran in, such aschrome. An open set: a cora that does not know a name, such as one a newer cora writes, keeps and compares it as it is.viewport(object, required): The size of the browser’s viewport the page was shown at.state(string): The name of the page state, reached by interaction, that the violation was seen in; absent for a page as it loads.element(object, required): The element the violation was seen on, on this page.
baseline.absent[].pages[].element
Section titled “baseline.absent[].pages[].element”fingerprint(string, required): The element fingerprint: a hash of the rule, the page’s host where it keeps one, its route key and the element’s path and selector, as 32 lowercase hexadecimal characters.path(array of objects, required): The iframes and shadow roots the element is inside, outermost first; empty for an element in the page’s own document.selector(string, required): The element’s CSS selector, in the document or shadow root the last hop leads into.