context-report 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- context_report/__init__.py +34 -0
- context_report/cli.py +121 -0
- context_report/data/__init__.py +1 -0
- context_report/data/applicability-v0.1.json +39 -0
- context_report/data/attestation-v0.1.schema.json +694 -0
- context_report/data/bundle-layout-v0.1.json +26 -0
- context_report/data/efficacy/directive_markers.json +13 -0
- context_report/data/efficacy/prompts/judge.md +13 -0
- context_report/data/efficacy/prompts/run_with_rule.md +3 -0
- context_report/data/efficacy/prompts/scenarios.md +10 -0
- context_report/data/payloads-v0.1.json +61 -0
- context_report/data/run-v0.1.schema.json +98 -0
- context_report/efficacy/__init__.py +23 -0
- context_report/efficacy/api_backend.py +45 -0
- context_report/efficacy/backends.py +63 -0
- context_report/efficacy/cache.py +95 -0
- context_report/efficacy/cli.py +186 -0
- context_report/efficacy/cli_backend.py +102 -0
- context_report/efficacy/core.py +277 -0
- context_report/efficacy/fastjudge.py +194 -0
- context_report/efficacy/grade.py +60 -0
- context_report/efficacy/pluginval.py +296 -0
- context_report/efficacy/prompts.py +36 -0
- context_report/efficacy/row.py +121 -0
- context_report/efficacy/rules.py +178 -0
- context_report/efficacy/scenarios.py +52 -0
- context_report/efficacy/stats.py +43 -0
- context_report/efficacy/suite.py +50 -0
- context_report/efficacy/transcripts.py +190 -0
- context_report/produce/__init__.py +1 -0
- context_report/produce/aggregate.py +209 -0
- context_report/produce/cost.py +230 -0
- context_report/produce/discover.py +140 -0
- context_report/produce/fault.py +144 -0
- context_report/produce/payloads.py +93 -0
- context_report/produce/reachability.py +177 -0
- context_report/produce/run.py +441 -0
- context_report/py.typed +0 -0
- context_report/rows.py +193 -0
- context_report/run/__init__.py +1 -0
- context_report/run/cards.py +81 -0
- context_report/run/cli.py +64 -0
- context_report/run/compare.py +155 -0
- context_report/run/evalcases.py +205 -0
- context_report/run/ingest_cli.py +68 -0
- context_report/run/judge.py +161 -0
- context_report/run/judge_cli.py +84 -0
- context_report/run/layout.py +186 -0
- context_report/run/manifest.py +222 -0
- context_report/run/runner.py +417 -0
- context_report/statement.py +133 -0
- context_report/verify.py +214 -0
- context_report-0.1.0.dist-info/METADATA +182 -0
- context_report-0.1.0.dist-info/RECORD +57 -0
- context_report-0.1.0.dist-info/WHEEL +4 -0
- context_report-0.1.0.dist-info/entry_points.txt +2 -0
- context_report-0.1.0.dist-info/licenses/LICENSE +202 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"""context-report: an open report format for whether an agent context artifact actually works.
|
|
2
|
+
|
|
3
|
+
Public API for library consumers (a catalog verifying a submitted statement, a CI job producing
|
|
4
|
+
one): everything in `__all__`. Anything else in this package is an implementation detail.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
# Set before the submodule imports below: produce.run reads context_report.__version__ at
|
|
10
|
+
# import time (it stamps producer.version), so this name must exist first or those imports
|
|
11
|
+
# circle back into a not-yet-initialized module.
|
|
12
|
+
__version__ = "0.1.0"
|
|
13
|
+
|
|
14
|
+
from context_report.produce.run import produce_statement
|
|
15
|
+
from context_report.run.compare import render_history, render_table
|
|
16
|
+
from context_report.run.layout import history_markdown, resolve_run_dir, rule_history_markdown
|
|
17
|
+
from context_report.run.manifest import load as load_manifest
|
|
18
|
+
from context_report.run.runner import run
|
|
19
|
+
from context_report.statement import validate
|
|
20
|
+
from context_report.verify import verify_statement as verify
|
|
21
|
+
|
|
22
|
+
__all__ = [
|
|
23
|
+
"__version__",
|
|
24
|
+
"history_markdown",
|
|
25
|
+
"load_manifest",
|
|
26
|
+
"produce_statement",
|
|
27
|
+
"render_history",
|
|
28
|
+
"render_table",
|
|
29
|
+
"resolve_run_dir",
|
|
30
|
+
"rule_history_markdown",
|
|
31
|
+
"run",
|
|
32
|
+
"validate",
|
|
33
|
+
"verify",
|
|
34
|
+
]
|
context_report/cli.py
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"""`context-report produce|verify`: statements of fact about artifacts, never verdicts on them."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import dataclasses
|
|
7
|
+
import json
|
|
8
|
+
import sys
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
from typing import Any
|
|
11
|
+
|
|
12
|
+
from context_report.efficacy.cli import add_efficacy_parser, run_efficacy
|
|
13
|
+
from context_report.produce.run import add_produce_parser, run_produce
|
|
14
|
+
from context_report.run.cli import add_run_parser, run_run
|
|
15
|
+
from context_report.run.ingest_cli import add_ingest_eval_parser, run_ingest_eval
|
|
16
|
+
from context_report.run.judge_cli import (
|
|
17
|
+
add_compare_parser,
|
|
18
|
+
add_judge_parser,
|
|
19
|
+
run_compare,
|
|
20
|
+
run_judge,
|
|
21
|
+
)
|
|
22
|
+
from context_report.verify import Verification, verify_statement
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _build_parser() -> argparse.ArgumentParser:
|
|
26
|
+
parser = argparse.ArgumentParser(prog="context-report")
|
|
27
|
+
subparsers = parser.add_subparsers(dest="command", required=True)
|
|
28
|
+
add_produce_parser(subparsers)
|
|
29
|
+
add_efficacy_parser(subparsers)
|
|
30
|
+
add_run_parser(subparsers)
|
|
31
|
+
add_ingest_eval_parser(subparsers)
|
|
32
|
+
add_judge_parser(subparsers)
|
|
33
|
+
add_compare_parser(subparsers)
|
|
34
|
+
|
|
35
|
+
verify_parser = subparsers.add_parser(
|
|
36
|
+
"verify",
|
|
37
|
+
help="check a statement is well-formed and, optionally, bound to a subject artifact",
|
|
38
|
+
)
|
|
39
|
+
verify_parser.add_argument("statement", help="path to the statement JSON file")
|
|
40
|
+
verify_parser.add_argument(
|
|
41
|
+
"--subject", default=None, help="path to the subject artifact (file or directory)"
|
|
42
|
+
)
|
|
43
|
+
verify_parser.add_argument(
|
|
44
|
+
"--json", action="store_true", dest="as_json", help="print the Verification as JSON"
|
|
45
|
+
)
|
|
46
|
+
return parser
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _human_report(verification: Verification) -> str:
|
|
50
|
+
lines = []
|
|
51
|
+
for row in verification.rows:
|
|
52
|
+
marker = " (author-reported)" if row.basis == "claimed" else ""
|
|
53
|
+
lines.append(f"{row.attribute} {row.basis} {row.result}{marker}")
|
|
54
|
+
lines.append("")
|
|
55
|
+
lines.append(
|
|
56
|
+
f"{len(verification.rows)} row(s): {len(verification.rederivable)} re-derivable, "
|
|
57
|
+
f"{len(verification.claimed)} claimed (author-reported), "
|
|
58
|
+
f"{len(verification.unmeasured)} unmeasured"
|
|
59
|
+
)
|
|
60
|
+
if verification.schema_errors:
|
|
61
|
+
lines.append(f"schema errors ({len(verification.schema_errors)}):")
|
|
62
|
+
lines.extend(f" - {e}" for e in verification.schema_errors)
|
|
63
|
+
if verification.subject_digest_matches is False:
|
|
64
|
+
lines.append("subject digest MISMATCH: this report does not describe the given artifact")
|
|
65
|
+
# Deliberately "well-formed and bound", never "good" or "passed" -- see Verification.ok.
|
|
66
|
+
lines.append(f"well-formed and bound: {verification.ok}")
|
|
67
|
+
return "\n".join(lines)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def _load_json(path: str) -> dict[str, Any]:
|
|
71
|
+
return json.loads(Path(path).read_text(encoding="utf-8"))
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def main(argv: list[str] | None = None) -> int:
|
|
75
|
+
"""CLI entry point. Returns an exit code; never raises SystemExit itself."""
|
|
76
|
+
parser = _build_parser()
|
|
77
|
+
try:
|
|
78
|
+
args = parser.parse_args(argv)
|
|
79
|
+
except SystemExit as exc:
|
|
80
|
+
return int(exc.code) if isinstance(exc.code, int) else 2
|
|
81
|
+
|
|
82
|
+
dispatch = {
|
|
83
|
+
"produce": run_produce,
|
|
84
|
+
"efficacy": run_efficacy,
|
|
85
|
+
"run": run_run,
|
|
86
|
+
"ingest-eval": run_ingest_eval,
|
|
87
|
+
"judge": run_judge,
|
|
88
|
+
"compare": run_compare,
|
|
89
|
+
}
|
|
90
|
+
if args.command in dispatch:
|
|
91
|
+
return dispatch[args.command](args)
|
|
92
|
+
if args.command != "verify":
|
|
93
|
+
return 2
|
|
94
|
+
return _run_verify(args)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def _run_verify(args: argparse.Namespace) -> int:
|
|
98
|
+
try:
|
|
99
|
+
stmt = _load_json(args.statement)
|
|
100
|
+
except (OSError, json.JSONDecodeError) as exc:
|
|
101
|
+
print(f"error: could not read {args.statement}: {exc}", file=sys.stderr) # noqa: T201
|
|
102
|
+
return 2
|
|
103
|
+
|
|
104
|
+
try:
|
|
105
|
+
verification = verify_statement(stmt, subject_path=args.subject)
|
|
106
|
+
except (OSError, KeyError, TypeError) as exc:
|
|
107
|
+
print(f"error: {exc}", file=sys.stderr) # noqa: T201
|
|
108
|
+
return 2
|
|
109
|
+
|
|
110
|
+
if args.as_json:
|
|
111
|
+
print(json.dumps(dataclasses.asdict(verification), indent=2)) # noqa: T201
|
|
112
|
+
else:
|
|
113
|
+
print(_human_report(verification)) # noqa: T201
|
|
114
|
+
|
|
115
|
+
if verification.schema_errors or verification.subject_digest_matches is False:
|
|
116
|
+
return 1
|
|
117
|
+
return 0
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
if __name__ == "__main__":
|
|
121
|
+
sys.exit(main())
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Package data: the shipped schema, byte-identical to spec/ (a test enforces it)."""
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_comment": "Which attributes do not apply to which subjectKind in v0.1. A (kind, attribute) pair listed here MUST be a NotApplicable row with reasoning; never omitted, never PASSED. Mirrors the 'Applies to' line of each section in spec/attestation/v0.1/attributes.md and the predicate-level conditionals in schema.json; tests/test_spec_prose.py holds the three together.",
|
|
3
|
+
"notApplicable": {
|
|
4
|
+
"plugin": [],
|
|
5
|
+
"instruction-file": [
|
|
6
|
+
"decision",
|
|
7
|
+
"fault.scriptMissing",
|
|
8
|
+
"fault.interpreterMissing",
|
|
9
|
+
"fault.timeout",
|
|
10
|
+
"fault.malformedOutput",
|
|
11
|
+
"cost.latency_ms"
|
|
12
|
+
],
|
|
13
|
+
"skill": [
|
|
14
|
+
"decision",
|
|
15
|
+
"fault.scriptMissing",
|
|
16
|
+
"fault.interpreterMissing",
|
|
17
|
+
"fault.timeout",
|
|
18
|
+
"fault.malformedOutput",
|
|
19
|
+
"cost.latency_ms"
|
|
20
|
+
],
|
|
21
|
+
"subagent": [
|
|
22
|
+
"decision",
|
|
23
|
+
"fault.scriptMissing",
|
|
24
|
+
"fault.interpreterMissing",
|
|
25
|
+
"fault.timeout",
|
|
26
|
+
"fault.malformedOutput",
|
|
27
|
+
"cost.latency_ms",
|
|
28
|
+
"interference"
|
|
29
|
+
],
|
|
30
|
+
"mcp-server": [
|
|
31
|
+
"decision",
|
|
32
|
+
"interference"
|
|
33
|
+
],
|
|
34
|
+
"hook": [
|
|
35
|
+
"cost.context_tokens",
|
|
36
|
+
"efficacy"
|
|
37
|
+
]
|
|
38
|
+
}
|
|
39
|
+
}
|