oc_chat
Loading...
Searching...
No Matches
report.py
Go to the documentation of this file.
1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3# oc_chat/testing/report.py
4
5
6# OCT-LINT: disable=no_hardcoded_secrets reason="Section-12.4 requires the 9xxx extension-code catalog to be documented here; catalog doc strings and the module docstring are prose, not credentials"
7"""
8Report-layer constants and pure mappings for the §20 stand-in (Plan 184).
9
10Purpose
11-------
12Pin everything the spec-10 section 11 and section 20.3 report
13contract fixes at the data level: the ``oct-test/v0.4`` schema stamp,
14the pinned ``supported_features`` values VERBATIM, the required-field
15path list, the documented 9xxx implementation-code catalog (section
1612.4 requires the implementation to document its extension codes in
17its own catalog — this module IS that catalog), and the section-4
18exit-code precedence.
19
20Responsibilities
21----------------
22- ``SCHEMA_STAMP`` / ``SUPPORTED_FEATURES`` / ``REQUIRED_FIELD_PATHS``.
23- ``IMPLEMENTATION_ERROR_CODES`` — every 9xxx code the stand-in emits.
24- ``make_error`` / ``make_violation`` — the §11 pinned entry shapes.
25- ``compute_exit_and_status`` — §4 precedence (4 over 3 over 2 over 1
26 over 0) with the §12.3 interrupted-status carve-out.
27
28Diagnostics
29-----------
30Domain: OC_TESTING
31Levels:
32 L2 — lifecycle events
33 L3 — semantic details
34 L4 — deep tracing
35
36Contracts
37---------
38- ``supported_features`` values are the §20.3 pinned set verbatim; a
39 serial stand-in reports ``workers_auto: "deferred"``. Since Plan 240
40 the stand-in can also DISTRIBUTE, and ADR-T-11's v0.3 amendment
41 (readiness audit A-19) makes that one value run-dependent —
42 ``"deferred"`` when serial, ``"enforced"`` when the run resolved
43 ``auto`` and distributed. This constant stays the SERIAL baseline;
44 ``runner._features_for`` applies the parallel value per run, so the
45 pinned dict below is still exactly what a serial report carries.
46- Timeout counts drive the ``failed`` status class (§11 status rule):
47 ``failed`` exactly when ``summary.failed + summary.timeout > 0``.
48
49Dependencies
50------------
51- oc_diagnostics (structured debug logging via _dbg)
52"""
53from __future__ import annotations
54
55from oc_diagnostics import _dbg
56
57#: §20.3: the stand-in emits the CURRENT report shape and its stamp.
58SCHEMA_STAMP: str = "oct-test/v0.4"
59
60#: §20.3 pinned stand-in values, VERBATIM (readiness audit A-19).
61SUPPORTED_FEATURES: dict[str, str] = {
62 "cwd_chdir": "enforced",
63 "env_mutation": "enforced",
64 "owned_writes_outside_tmp": "advisory",
65 "singleton_reset": "deferred",
66 "lock_target_outside_tmp": "deferred",
67 "network_marker": "deferred",
68 "large_suite_pagination": "deferred",
69 "workers_auto": "deferred",
70 "error_code_catalog": "enforced",
71 "signal_handling": "enforced",
72 "per_test_timeout": "enforced",
73 "single_package_walk": "enforced",
74}
75
76#: The §20.3 output subset spelled out as leaf paths (v0.4.2 text).
77#: The schema-shape acceptance test pins its own independent copy.
78REQUIRED_FIELD_PATHS: tuple[str, ...] = (
79 "schema",
80 "run_id",
81 "status",
82 "exit_code",
83 "workspace.root",
84 "workspace.mode",
85 "selection.packages",
86 "selection.profile",
87 "selection.marker",
88 "selection.seed",
89 "selection.nodeids",
90 "selection.pytest_args",
91 "workers.requested",
92 "workers.actual",
93 "workers.dist_mode",
94 "summary",
95 "tests",
96 "contract_violations",
97 "artifacts.junit_xml",
98 "artifacts.ndjson",
99 "artifacts.ndjson_stream",
100 "errors",
101 "supported_features",
102)
103
104#: §12.4 implementation-specific extension codes — the stand-in's own
105#: catalog. Consumers MUST tolerate unknown 9xxx codes; these are ours.
106IMPLEMENTATION_ERROR_CODES: dict[str, str] = {
107 # OCT-LINT: disable=no_hardcoded_secrets reason="Section-12.4 requires the 9xxx extension-code catalog to be documented here; catalog doc strings and the module docstring are prose, not credentials"
108 "9001": ("WORKERS_INVALID — the --workers value is neither a positive "
109 "integer nor the token 'auto' (section 12.7 reserves invalid "
110 "worker counts for a documented 9xxx code)."),
111 "9002": ("STANDIN_INTERNAL_ERROR — an unexpected exception escaped the "
112 "stand-in orchestrator; the exception class and message are "
113 "carried in the error message."),
114 # OCT-LINT: disable=no_hardcoded_secrets reason="Section-12.4 requires the 9xxx extension-code catalog to be documented here; catalog doc strings and the module docstring are prose, not credentials"
115 "9003": ("STANDIN_UNSUPPORTED_FLAG — a flag that exists in the section-4 "
116 "v1.0 grammar (--workspace, --ndjson) is not supported by the "
117 "section-20 stand-in; exit 4, configuration class (section "
118 "20.1: --workspace rejection is never exit 2)."),
119 "9004": ("SEED_INVALID — the --seed value is not an integer."),
120 # OCT-LINT: disable=no_hardcoded_secrets reason="Section-12.4 requires the 9xxx extension-code catalog to be documented here; catalog doc strings and the module docstring are prose, not credentials"
121 "9005": ("PER_TEST_TIMEOUT_INVALID — the --per-test-timeout value is "
122 "not a positive integer number of seconds."),
123 # OCT-LINT: disable=no_hardcoded_secrets reason="Section-12.4 requires the 9xxx extension-code catalog to be documented here; catalog doc strings and the module docstring are prose, not credentials"
124 "9006": ("OUTPUT_TESTS_LIMIT_INVALID — the --output-tests-limit value "
125 "is not a positive integer (the flag itself is otherwise "
126 "accepted and ignored per the section-20.3 no-sink rule)."),
127 # OCT-LINT: disable=no_hardcoded_secrets reason="Section-12.4 requires the 9xxx extension-code catalog to be documented here; catalog doc strings and the module docstring are prose, not credentials"
128 "9007": ("WORKERS_CLAMPED — the requested --workers count exceeded the "
129 "workspace manifest's max_workers cap for this package and was "
130 "clamped to it; the run continued at the cap. Warning "
131 "severity: the run is valid, it simply used fewer workers "
132 "than asked for (Plan 240 P2)."),
133 "9008": ("PYTEST_UNEXPECTED_EXIT — the in-process pytest run returned "
134 "an exit class the stand-in did not produce itself (internal "
135 "error or usage error); the pytest exit code is in the "
136 "message."),
137}
138
139#: Top-level status enum (§11).
140STATUSES: tuple[str, ...] = (
141 "passed", "failed", "contract_violation", "orchestrator_error",
142 "orchestrator_interrupted", "configuration_error",
143)
144
145
147 kind: str,
148 code: str,
149 severity: str,
150 message: str,
151 source: str = "orchestrator",
152) -> dict:
153 """Build a §11 ``errors[]`` entry ``{kind, code, severity, message,
154 source}``."""
155 func = "make_error"
156 _dbg("OC_TESTING", func, f"{kind}/{code}/{severity}", 4)
157 return {
158 "kind": kind,
159 "code": code,
160 "severity": severity,
161 "message": message,
162 "source": source,
163 }
164
165
167 rule_id: str,
168 file: str,
169 nodeid: str | None,
170 severity: str,
171 message: str,
172) -> dict:
173 """Build a §11 ``contract_violations[]`` entry ``{rule_id, file,
174 nodeid, severity, message}`` (nodeid ``None`` for file/run-level
175 findings)."""
176 func = "make_violation"
177 _dbg("OC_TESTING", func, f"{rule_id}@{file}", 4)
178 return {
179 "rule_id": rule_id,
180 "file": file,
181 "nodeid": nodeid,
182 "severity": severity,
183 "message": message,
184 }
185
186
188 *,
189 fatal_config: bool,
190 interrupted: bool,
191 orchestrator_error: bool,
192 error_violations: bool,
193 failed_or_timeout: bool,
194) -> tuple[int, str]:
195 """§4 exit precedence: 4 over 3 over 2 over 1 over 0.
196
197 ``interrupted`` and ``orchestrator_error`` share exit 3; the
198 interrupted STATUS wins when both hold (§12.6: an
199 ``ORCHESTRATOR_INTERRUPTED`` signal already forced exit 3).
200 """
201 func = "compute_exit_and_status"
202 if fatal_config:
203 result = (4, "configuration_error")
204 elif interrupted:
205 result = (3, "orchestrator_interrupted")
206 elif orchestrator_error:
207 result = (3, "orchestrator_error")
208 elif error_violations:
209 result = (2, "contract_violation")
210 elif failed_or_timeout:
211 result = (1, "failed")
212 else:
213 result = (0, "passed")
214 _dbg("OC_TESTING", func, f"-> {result}", 4)
215 return result
216
217
218_dbg("OC_TESTING", "module", "loaded", 4)
219
220__all__ = [
221 "SCHEMA_STAMP",
222 "SUPPORTED_FEATURES",
223 "REQUIRED_FIELD_PATHS",
224 "IMPLEMENTATION_ERROR_CODES",
225 "STATUSES",
226 "make_error",
227 "make_violation",
228 "compute_exit_and_status",
229]
dict make_violation(str rule_id, str file, str|None nodeid, str severity, str message)
Definition report.py:172
dict make_error(str kind, str code, str severity, str message, str source="orchestrator")
Definition report.py:152
tuple[int, str] compute_exit_and_status(*, bool fatal_config, bool interrupted, bool orchestrator_error, bool error_violations, bool failed_or_timeout)
Definition report.py:194