vigil-codeintel 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.
- vigil_codeintel-0.1.0.dist-info/METADATA +780 -0
- vigil_codeintel-0.1.0.dist-info/RECORD +131 -0
- vigil_codeintel-0.1.0.dist-info/WHEEL +5 -0
- vigil_codeintel-0.1.0.dist-info/entry_points.txt +3 -0
- vigil_codeintel-0.1.0.dist-info/licenses/LICENSE +21 -0
- vigil_codeintel-0.1.0.dist-info/top_level.txt +3 -0
- vigil_forensic/__init__.py +224 -0
- vigil_forensic/_git_utils.py +178 -0
- vigil_forensic/_shared.py +510 -0
- vigil_forensic/_stubs.py +156 -0
- vigil_forensic/gate_checks/__init__.py +1 -0
- vigil_forensic/gate_checks/_ast_helpers.py +629 -0
- vigil_forensic/gate_checks/_deployment_detector.py +573 -0
- vigil_forensic/gate_checks/atomic_write_checks.py +1143 -0
- vigil_forensic/gate_checks/authority_checks.py +95 -0
- vigil_forensic/gate_checks/boundary_breach_checks.py +202 -0
- vigil_forensic/gate_checks/broad_except_checks.py +301 -0
- vigil_forensic/gate_checks/broad_except_hidden_sentinel_checks.py +365 -0
- vigil_forensic/gate_checks/common.py +253 -0
- vigil_forensic/gate_checks/config_safety_checks.py +704 -0
- vigil_forensic/gate_checks/config_ssot_checks.py +78 -0
- vigil_forensic/gate_checks/conflict_checks.py +193 -0
- vigil_forensic/gate_checks/context_fallback_checks.py +697 -0
- vigil_forensic/gate_checks/context_health_checks.py +289 -0
- vigil_forensic/gate_checks/contract_shape_drift_checks.py +459 -0
- vigil_forensic/gate_checks/dirty_baseline_check.py +274 -0
- vigil_forensic/gate_checks/duplication_checks.py +387 -0
- vigil_forensic/gate_checks/embedded_string_checks.py +123 -0
- vigil_forensic/gate_checks/empty_output_checks.py +87 -0
- vigil_forensic/gate_checks/encoding_checks.py +847 -0
- vigil_forensic/gate_checks/export_completeness_checks.py +156 -0
- vigil_forensic/gate_checks/fallback_checks.py +41 -0
- vigil_forensic/gate_checks/file_proliferation_checks.py +171 -0
- vigil_forensic/gate_checks/fix_without_test_checks.py +69 -0
- vigil_forensic/gate_checks/forensic_cluster_runners/__init__.py +9 -0
- vigil_forensic/gate_checks/forensic_cluster_runners/_helpers.py +71 -0
- vigil_forensic/gate_checks/forensic_cluster_runners/advanced_checks.py +322 -0
- vigil_forensic/gate_checks/forensic_cluster_runners/core.py +273 -0
- vigil_forensic/gate_checks/forensic_cluster_runners/integrity_checks.py +203 -0
- vigil_forensic/gate_checks/forensic_cluster_runners/quality_checks.py +666 -0
- vigil_forensic/gate_checks/forensic_clusters/__init__.py +193 -0
- vigil_forensic/gate_checks/forensic_clusters/allowlist.py +426 -0
- vigil_forensic/gate_checks/forensic_clusters/allowlist_writer.py +302 -0
- vigil_forensic/gate_checks/forensic_clusters/api_protocol.py +231 -0
- vigil_forensic/gate_checks/forensic_clusters/async_quality.py +1156 -0
- vigil_forensic/gate_checks/forensic_clusters/code_style.py +808 -0
- vigil_forensic/gate_checks/forensic_clusters/core.py +319 -0
- vigil_forensic/gate_checks/forensic_clusters/data_quality.py +763 -0
- vigil_forensic/gate_checks/forensic_clusters/dead_code.py +480 -0
- vigil_forensic/gate_checks/forensic_clusters/edit_mutation.py +842 -0
- vigil_forensic/gate_checks/forensic_clusters/exception_boundary.py +240 -0
- vigil_forensic/gate_checks/forensic_clusters/legacy_debt.py +556 -0
- vigil_forensic/gate_checks/forensic_clusters/static_analysis.py +834 -0
- vigil_forensic/gate_checks/forensic_clusters/structural_quality.py +298 -0
- vigil_forensic/gate_checks/god_object_zones_checks.py +173 -0
- vigil_forensic/gate_checks/hallucination_checks.py +566 -0
- vigil_forensic/gate_checks/hunter_artifact_completeness_check.py +139 -0
- vigil_forensic/gate_checks/implementation_overfit_checks.py +380 -0
- vigil_forensic/gate_checks/import_integrity_checks.py +233 -0
- vigil_forensic/gate_checks/imports_in_function_checks.py +283 -0
- vigil_forensic/gate_checks/ml_checks.py +318 -0
- vigil_forensic/gate_checks/performance_checks.py +106 -0
- vigil_forensic/gate_checks/project_specific_runner.py +691 -0
- vigil_forensic/gate_checks/provider_capability_checks.py +73 -0
- vigil_forensic/gate_checks/refactor_completeness_checks.py +274 -0
- vigil_forensic/gate_checks/reliability_checks.py +389 -0
- vigil_forensic/gate_checks/reporting_checks.py +55 -0
- vigil_forensic/gate_checks/runtime_behavior_checks.py +220 -0
- vigil_forensic/gate_checks/security_injection_checks.py +332 -0
- vigil_forensic/gate_checks/semantic_intent_checks.py +139 -0
- vigil_forensic/gate_checks/size_complexity_checks.py +336 -0
- vigil_forensic/gate_checks/stuck_feature_flag_checks.py +354 -0
- vigil_forensic/gate_checks/syntax_validity_checks.py +217 -0
- vigil_forensic/gate_checks/temporal_freshness_checks.py +79 -0
- vigil_forensic/gate_checks/test_quality_checks.py +946 -0
- vigil_forensic/gate_checks/testing_checks.py +149 -0
- vigil_forensic/gate_checks/toctou_checks.py +367 -0
- vigil_forensic/gate_checks/type_checking_checks.py +316 -0
- vigil_forensic/gate_models.py +392 -0
- vigil_forensic/gate_packs/__init__.py +1 -0
- vigil_forensic/gate_packs/universal.py +179 -0
- vigil_forensic/gate_profile.json +31 -0
- vigil_forensic/gate_registry.py +21 -0
- vigil_forensic/language_profiles.py +219 -0
- vigil_forensic/meta_findings.py +207 -0
- vigil_forensic/self_audit.py +725 -0
- vigil_forensic/source_analysis.py +175 -0
- vigil_mapper/__init__.py +103 -0
- vigil_mapper/_ast_helpers_minimal.py +229 -0
- vigil_mapper/_extract_imports_impl.py +123 -0
- vigil_mapper/_file_count_guard.py +129 -0
- vigil_mapper/_git_utils.py +178 -0
- vigil_mapper/_runtime_ast.py +438 -0
- vigil_mapper/_runtime_dispatch.py +137 -0
- vigil_mapper/_seed_helpers.py +82 -0
- vigil_mapper/authority_builder.py +1102 -0
- vigil_mapper/cli_entry.py +731 -0
- vigil_mapper/conflict_builder.py +818 -0
- vigil_mapper/data_contract_builder.py +446 -0
- vigil_mapper/findings_builder.py +716 -0
- vigil_mapper/fingerprint.py +53 -0
- vigil_mapper/hotspot_builder.py +539 -0
- vigil_mapper/map_common.py +449 -0
- vigil_mapper/map_errors.py +55 -0
- vigil_mapper/map_models.py +431 -0
- vigil_mapper/map_models_ext.py +206 -0
- vigil_mapper/map_models_findings.py +130 -0
- vigil_mapper/map_storage.py +455 -0
- vigil_mapper/parse_cache.py +795 -0
- vigil_mapper/refactor_boundary_builder.py +266 -0
- vigil_mapper/runtime_builder.py +527 -0
- vigil_mapper/runtime_tracer.py +243 -0
- vigil_mapper/runtime_tracer_entry.py +199 -0
- vigil_mapper/semantic_diff.py +71 -0
- vigil_mapper/source_adapters/__init__.py +109 -0
- vigil_mapper/source_adapters/_base.py +264 -0
- vigil_mapper/source_adapters/_ir.py +156 -0
- vigil_mapper/source_adapters/_lexer.py +309 -0
- vigil_mapper/source_adapters/_patterns.py +212 -0
- vigil_mapper/source_adapters/_treesitter.py +182 -0
- vigil_mapper/source_adapters/go.py +553 -0
- vigil_mapper/source_adapters/java.py +541 -0
- vigil_mapper/source_adapters/javascript.py +626 -0
- vigil_mapper/source_adapters/python.py +325 -0
- vigil_mapper/source_adapters/typescript.py +749 -0
- vigil_mapper/structural_builder.py +586 -0
- vigil_mcp/__init__.py +1 -0
- vigil_mcp/_jobs.py +587 -0
- vigil_mcp/_paths.py +93 -0
- vigil_mcp/forensic_server.py +419 -0
- vigil_mcp/map_server.py +452 -0
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
"""Context health gate (B3 wave, 2026-04-23).
|
|
2
|
+
|
|
3
|
+
The autoforensics system previously had a silent failure mode: when the
|
|
4
|
+
``PostExecGateContext`` was assembled with empty fields (e.g. ``file_snapshots
|
|
5
|
+
== {}`` because snapshot collection failed upstream, or ``touched_files == ()``
|
|
6
|
+
because the changed-files list was lost), every write-safety gate would
|
|
7
|
+
trivially return "no findings". The report would read PASS even though no
|
|
8
|
+
meaningful audit actually happened.
|
|
9
|
+
|
|
10
|
+
This gate closes that gap. It runs FIRST in the dispatch order (conceptually
|
|
11
|
+
— ordering is enforced by GATE_SPECS position) and emits meta-level findings
|
|
12
|
+
describing exactly which context slots were unpopulated and why that matters.
|
|
13
|
+
|
|
14
|
+
Design rules
|
|
15
|
+
------------
|
|
16
|
+
* Runs in BOTH static (sessionless) and full-audit modes. It is the single
|
|
17
|
+
gate whose job is to tell you whether the OTHER gates had enough context
|
|
18
|
+
to produce meaningful results.
|
|
19
|
+
* Uses ``attempt_id`` to detect static mode — the static CLI sets
|
|
20
|
+
``attempt_id="forensic_audit_static"`` / ``self_audit`` (see
|
|
21
|
+
``cli_forensic_audit._build_static_context`` and
|
|
22
|
+
``self_audit.build_synthetic_context``). In static mode we deliberately
|
|
23
|
+
suppress findings that are expected to be empty (e.g. empty
|
|
24
|
+
``file_snapshots`` is the normal case for the CLI static runner).
|
|
25
|
+
* Emits findings via the shared ``build_finding`` helper so they flow through
|
|
26
|
+
the same allowlist / severity override machinery as the other gates. It
|
|
27
|
+
does NOT use ``meta_findings.emit_meta_finding`` because this gate runs
|
|
28
|
+
in-band (it's a real gate runner, not an out-of-band emitter).
|
|
29
|
+
"""
|
|
30
|
+
from __future__ import annotations
|
|
31
|
+
|
|
32
|
+
import logging
|
|
33
|
+
|
|
34
|
+
from vigil_forensic._shared import (
|
|
35
|
+
EvidenceReference,
|
|
36
|
+
GateCategory,
|
|
37
|
+
GateCheckResult,
|
|
38
|
+
GateFinding,
|
|
39
|
+
GateImpact,
|
|
40
|
+
GateSeverity,
|
|
41
|
+
)
|
|
42
|
+
from vigil_forensic.gate_models import PostExecGateContext
|
|
43
|
+
|
|
44
|
+
from .common import build_check_result, build_finding
|
|
45
|
+
|
|
46
|
+
_log = logging.getLogger(__name__)
|
|
47
|
+
|
|
48
|
+
# Static-mode attempt_id sentinel values. Kept here rather than imported from
|
|
49
|
+
# cli_forensic_audit to avoid a circular import between gate_checks/* and
|
|
50
|
+
# BRAIN/autoforensics/cli_forensic_audit.py.
|
|
51
|
+
_STATIC_MODE_ATTEMPT_IDS: frozenset[str] = frozenset({
|
|
52
|
+
"forensic_audit_static",
|
|
53
|
+
"self_audit",
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def _is_static_mode(ctx: PostExecGateContext) -> bool:
|
|
58
|
+
"""Return True if the context was assembled by the static CLI runners.
|
|
59
|
+
|
|
60
|
+
Static-mode contexts legitimately have empty ``file_snapshots`` (self_audit
|
|
61
|
+
populates them, but cli_forensic_audit builds them lazily on access),
|
|
62
|
+
empty ``session_artifacts``, missing git state, etc. Suppressing findings
|
|
63
|
+
in that mode avoids drowning the report in meta-noise when the user is
|
|
64
|
+
intentionally running a sessionless scan.
|
|
65
|
+
"""
|
|
66
|
+
return ctx.attempt_id in _STATIC_MODE_ATTEMPT_IDS
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def _has_git_state(ctx: PostExecGateContext) -> bool:
|
|
70
|
+
"""Detect whether the context carries git-derived state.
|
|
71
|
+
|
|
72
|
+
``PostExecGateContext`` does not have a dedicated ``git_state`` attribute
|
|
73
|
+
in the current data model — git-dependent information is scattered across
|
|
74
|
+
``runtime_state.extras``, ``forensic_report``, and per-gate git_show
|
|
75
|
+
probes. We treat "git state available" as any of:
|
|
76
|
+
|
|
77
|
+
* ``ctx.runtime_state.extras`` carries a key containing "git";
|
|
78
|
+
* ``ctx.artifact_refs`` references a git artifact;
|
|
79
|
+
* ``ctx.forensic_report`` has a non-empty ``current_task_id`` (implies
|
|
80
|
+
a live session with git history reachable).
|
|
81
|
+
|
|
82
|
+
This heuristic is intentionally generous: we only want to emit a finding
|
|
83
|
+
when NO path to git state is available, not every time a particular
|
|
84
|
+
optional field is empty.
|
|
85
|
+
"""
|
|
86
|
+
# Runtime-state extras often carry git_hash, git_branch, etc.
|
|
87
|
+
try:
|
|
88
|
+
for key, _val in ctx.runtime_state.extras:
|
|
89
|
+
if "git" in str(key).lower():
|
|
90
|
+
return True
|
|
91
|
+
except AttributeError:
|
|
92
|
+
pass
|
|
93
|
+
|
|
94
|
+
# Artifact references — e.g., git_blame_<file>.txt
|
|
95
|
+
for key in ctx.artifact_refs.keys():
|
|
96
|
+
if "git" in str(key).lower():
|
|
97
|
+
return True
|
|
98
|
+
|
|
99
|
+
# Live session with current_task_id implies git history reachable
|
|
100
|
+
current_task = getattr(ctx.forensic_report, "current_task_id", None)
|
|
101
|
+
if current_task:
|
|
102
|
+
return True
|
|
103
|
+
|
|
104
|
+
return False
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def _session_dir_exists(ctx: PostExecGateContext) -> bool:
|
|
108
|
+
"""Return True if the expected session artifact directory exists on disk.
|
|
109
|
+
|
|
110
|
+
Only meaningful when ``session_number > 0`` (i.e. we're in an active
|
|
111
|
+
session, not a static scan). Layout follows the project convention of
|
|
112
|
+
``<project_dir>/.cortex/sessions/<session_number>/``.
|
|
113
|
+
"""
|
|
114
|
+
if ctx.session_number <= 0:
|
|
115
|
+
return True # no session → no directory expected
|
|
116
|
+
session_dir = ctx.project_dir / ".cortex" / "sessions" / str(ctx.session_number)
|
|
117
|
+
try:
|
|
118
|
+
return session_dir.is_dir()
|
|
119
|
+
except OSError as exc:
|
|
120
|
+
_log.warning(
|
|
121
|
+
"context_health: OSError probing session dir %s: %s", session_dir, exc,
|
|
122
|
+
)
|
|
123
|
+
# If we can't even probe the directory, downstream gates will also
|
|
124
|
+
# struggle — surface it as "missing" to be safe.
|
|
125
|
+
return False
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def run_context_health_checks(ctx: PostExecGateContext) -> GateCheckResult:
|
|
129
|
+
"""Emit meta-level findings describing gaps in the audit context itself.
|
|
130
|
+
|
|
131
|
+
Runs in BOTH static and full-audit modes. Findings that would be
|
|
132
|
+
expected in static mode (empty snapshots, no git state, no session dir)
|
|
133
|
+
are suppressed when ``_is_static_mode(ctx)`` is True so the noise floor
|
|
134
|
+
stays meaningful.
|
|
135
|
+
"""
|
|
136
|
+
findings: list[GateFinding] = []
|
|
137
|
+
static = _is_static_mode(ctx)
|
|
138
|
+
|
|
139
|
+
# 1. Empty file_snapshots outside static mode -----------------------------
|
|
140
|
+
# This is the original motivating failure: write-safety gates silently
|
|
141
|
+
# pass when they have no snapshots to inspect. In static mode,
|
|
142
|
+
# cli_forensic_audit intentionally leaves snapshots empty (gates read
|
|
143
|
+
# files on demand from disk), so we only fire outside that mode.
|
|
144
|
+
if not static and not ctx.file_snapshots:
|
|
145
|
+
findings.append(
|
|
146
|
+
build_finding(
|
|
147
|
+
check_id="context_health.empty_file_snapshots",
|
|
148
|
+
category=GateCategory.META,
|
|
149
|
+
title="Audit context has no file snapshots",
|
|
150
|
+
severity=GateSeverity.HIGH,
|
|
151
|
+
impact=GateImpact.WARN,
|
|
152
|
+
summary=(
|
|
153
|
+
"ctx.file_snapshots is empty outside static-scan mode. "
|
|
154
|
+
"Write-safety gates (atomic_write, empty_output, "
|
|
155
|
+
"contract_shape_drift, etc.) use snapshots to reason "
|
|
156
|
+
"about file content and will silently produce 0 findings "
|
|
157
|
+
"when the map is empty. A PASS verdict in that state is "
|
|
158
|
+
"meaningless."
|
|
159
|
+
),
|
|
160
|
+
recommendation=(
|
|
161
|
+
"Populate ctx.file_snapshots in the upstream gate "
|
|
162
|
+
"pipeline before dispatch, OR treat this finding as a "
|
|
163
|
+
"hard failure of the gate infrastructure (not of the "
|
|
164
|
+
"project under audit)."
|
|
165
|
+
),
|
|
166
|
+
evidence=[
|
|
167
|
+
EvidenceReference(
|
|
168
|
+
kind="context_slot",
|
|
169
|
+
path="ctx.file_snapshots",
|
|
170
|
+
detail=f"attempt_id={ctx.attempt_id!r} task_id={ctx.task_id!r}",
|
|
171
|
+
ok=False,
|
|
172
|
+
)
|
|
173
|
+
],
|
|
174
|
+
allowlist_allowed=False,
|
|
175
|
+
)
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
# 2. Missing git state ----------------------------------------------------
|
|
179
|
+
# Gates that rely on diff/blame/authorship (authority_checks,
|
|
180
|
+
# contract_shape_drift) will be inconclusive. Emit MEDIUM so operators
|
|
181
|
+
# know findings from those gates may be incomplete.
|
|
182
|
+
if not static and not _has_git_state(ctx):
|
|
183
|
+
findings.append(
|
|
184
|
+
build_finding(
|
|
185
|
+
check_id="context_health.git_state_unavailable",
|
|
186
|
+
category=GateCategory.META,
|
|
187
|
+
title="Audit context is missing git state",
|
|
188
|
+
severity=GateSeverity.MEDIUM,
|
|
189
|
+
impact=GateImpact.WARN,
|
|
190
|
+
summary=(
|
|
191
|
+
"No git-derived state attached to context (no git keys "
|
|
192
|
+
"in runtime_state.extras, no git artifact refs, no "
|
|
193
|
+
"current_task_id). Gates depending on diff / blame / "
|
|
194
|
+
"authorship are inconclusive."
|
|
195
|
+
),
|
|
196
|
+
recommendation=(
|
|
197
|
+
"Ensure the gate pipeline captures git state upstream "
|
|
198
|
+
"(git rev-parse / git show) when a git repo is "
|
|
199
|
+
"available. If the project is intentionally not a git "
|
|
200
|
+
"repo, disable git-dependent gates explicitly."
|
|
201
|
+
),
|
|
202
|
+
evidence=[
|
|
203
|
+
EvidenceReference(
|
|
204
|
+
kind="context_slot",
|
|
205
|
+
path="ctx.runtime_state/artifact_refs/forensic_report",
|
|
206
|
+
detail="no git-prefixed key found",
|
|
207
|
+
ok=False,
|
|
208
|
+
)
|
|
209
|
+
],
|
|
210
|
+
allowlist_allowed=True,
|
|
211
|
+
)
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
# 3. Session artifacts missing -------------------------------------------
|
|
215
|
+
# session_number is set but the expected artifact directory is absent.
|
|
216
|
+
# This typically means an interrupted session or out-of-band cleanup.
|
|
217
|
+
if ctx.session_number > 0 and not _session_dir_exists(ctx):
|
|
218
|
+
session_dir = ctx.project_dir / ".cortex" / "sessions" / str(ctx.session_number)
|
|
219
|
+
findings.append(
|
|
220
|
+
build_finding(
|
|
221
|
+
check_id="context_health.session_artifacts_missing",
|
|
222
|
+
category=GateCategory.META,
|
|
223
|
+
title="Session artifacts directory is missing",
|
|
224
|
+
severity=GateSeverity.MEDIUM,
|
|
225
|
+
impact=GateImpact.WARN,
|
|
226
|
+
summary=(
|
|
227
|
+
f"Expected session artifact dir {session_dir} does not "
|
|
228
|
+
f"exist, yet session_number={ctx.session_number} is set "
|
|
229
|
+
f"on the gate context."
|
|
230
|
+
),
|
|
231
|
+
recommendation=(
|
|
232
|
+
"Investigate why the session produced no artifact "
|
|
233
|
+
"directory (interrupted session, cleanup race, wrong "
|
|
234
|
+
"project_dir). Artifact-completeness gates cannot "
|
|
235
|
+
"produce meaningful output without it."
|
|
236
|
+
),
|
|
237
|
+
evidence=[
|
|
238
|
+
EvidenceReference(
|
|
239
|
+
kind="session_artifact_dir",
|
|
240
|
+
path=str(session_dir),
|
|
241
|
+
detail=f"session_number={ctx.session_number}",
|
|
242
|
+
ok=False,
|
|
243
|
+
)
|
|
244
|
+
],
|
|
245
|
+
allowlist_allowed=True,
|
|
246
|
+
)
|
|
247
|
+
)
|
|
248
|
+
|
|
249
|
+
# 4. Empty touched_files outside static mode ------------------------------
|
|
250
|
+
# This is a soft signal — a genuine no-op audit can produce empty
|
|
251
|
+
# touched_files legitimately. Surface it as LOW so it's visible but
|
|
252
|
+
# doesn't block.
|
|
253
|
+
if not static and not ctx.touched_files:
|
|
254
|
+
findings.append(
|
|
255
|
+
build_finding(
|
|
256
|
+
check_id="context_health.touched_files_empty",
|
|
257
|
+
category=GateCategory.META,
|
|
258
|
+
title="Audit context reports zero touched files",
|
|
259
|
+
severity=GateSeverity.LOW,
|
|
260
|
+
impact=GateImpact.WARN,
|
|
261
|
+
summary=(
|
|
262
|
+
"ctx.touched_files is empty outside static-scan mode. "
|
|
263
|
+
"May be a legitimate no-op audit (metadata-only) but "
|
|
264
|
+
"can also mean the upstream changed-files collector "
|
|
265
|
+
"lost its input."
|
|
266
|
+
),
|
|
267
|
+
recommendation=(
|
|
268
|
+
"Confirm the audit input is what you expect. If this "
|
|
269
|
+
"audit is genuinely no-op, suppress this finding via "
|
|
270
|
+
"allowlist; otherwise investigate the upstream "
|
|
271
|
+
"changed-files collector."
|
|
272
|
+
),
|
|
273
|
+
evidence=[
|
|
274
|
+
EvidenceReference(
|
|
275
|
+
kind="context_slot",
|
|
276
|
+
path="ctx.touched_files",
|
|
277
|
+
detail=f"attempt_id={ctx.attempt_id!r}",
|
|
278
|
+
ok=False,
|
|
279
|
+
)
|
|
280
|
+
],
|
|
281
|
+
allowlist_allowed=True,
|
|
282
|
+
)
|
|
283
|
+
)
|
|
284
|
+
|
|
285
|
+
return build_check_result(
|
|
286
|
+
check_id="context_health",
|
|
287
|
+
category=GateCategory.META,
|
|
288
|
+
findings=findings,
|
|
289
|
+
)
|