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.
Files changed (57) hide show
  1. context_report/__init__.py +34 -0
  2. context_report/cli.py +121 -0
  3. context_report/data/__init__.py +1 -0
  4. context_report/data/applicability-v0.1.json +39 -0
  5. context_report/data/attestation-v0.1.schema.json +694 -0
  6. context_report/data/bundle-layout-v0.1.json +26 -0
  7. context_report/data/efficacy/directive_markers.json +13 -0
  8. context_report/data/efficacy/prompts/judge.md +13 -0
  9. context_report/data/efficacy/prompts/run_with_rule.md +3 -0
  10. context_report/data/efficacy/prompts/scenarios.md +10 -0
  11. context_report/data/payloads-v0.1.json +61 -0
  12. context_report/data/run-v0.1.schema.json +98 -0
  13. context_report/efficacy/__init__.py +23 -0
  14. context_report/efficacy/api_backend.py +45 -0
  15. context_report/efficacy/backends.py +63 -0
  16. context_report/efficacy/cache.py +95 -0
  17. context_report/efficacy/cli.py +186 -0
  18. context_report/efficacy/cli_backend.py +102 -0
  19. context_report/efficacy/core.py +277 -0
  20. context_report/efficacy/fastjudge.py +194 -0
  21. context_report/efficacy/grade.py +60 -0
  22. context_report/efficacy/pluginval.py +296 -0
  23. context_report/efficacy/prompts.py +36 -0
  24. context_report/efficacy/row.py +121 -0
  25. context_report/efficacy/rules.py +178 -0
  26. context_report/efficacy/scenarios.py +52 -0
  27. context_report/efficacy/stats.py +43 -0
  28. context_report/efficacy/suite.py +50 -0
  29. context_report/efficacy/transcripts.py +190 -0
  30. context_report/produce/__init__.py +1 -0
  31. context_report/produce/aggregate.py +209 -0
  32. context_report/produce/cost.py +230 -0
  33. context_report/produce/discover.py +140 -0
  34. context_report/produce/fault.py +144 -0
  35. context_report/produce/payloads.py +93 -0
  36. context_report/produce/reachability.py +177 -0
  37. context_report/produce/run.py +441 -0
  38. context_report/py.typed +0 -0
  39. context_report/rows.py +193 -0
  40. context_report/run/__init__.py +1 -0
  41. context_report/run/cards.py +81 -0
  42. context_report/run/cli.py +64 -0
  43. context_report/run/compare.py +155 -0
  44. context_report/run/evalcases.py +205 -0
  45. context_report/run/ingest_cli.py +68 -0
  46. context_report/run/judge.py +161 -0
  47. context_report/run/judge_cli.py +84 -0
  48. context_report/run/layout.py +186 -0
  49. context_report/run/manifest.py +222 -0
  50. context_report/run/runner.py +417 -0
  51. context_report/statement.py +133 -0
  52. context_report/verify.py +214 -0
  53. context_report-0.1.0.dist-info/METADATA +182 -0
  54. context_report-0.1.0.dist-info/RECORD +57 -0
  55. context_report-0.1.0.dist-info/WHEEL +4 -0
  56. context_report-0.1.0.dist-info/entry_points.txt +2 -0
  57. 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
+ }