Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/validate.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: Validate Request Documents

on:
workflow_run:
workflow_dispatch:
pull_request:
branches:
- main
Expand Down
4 changes: 4 additions & 0 deletions claims/nyt/ai-backlash.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
sourceUriDigest: "f217d823160d39ca379a09044e1242ac641c8b1d79a1d6f499c59f08a1b67500"
summary: "The global push for AI infrastructure is increasingly clashing with local environmental and economic limits. In the U.S., massive data center expansion has sparked significant resistance due to the immense electricity and water these facilities require, which threatens to strain power grids and increase costs for residents. This tension represents a broader international challenge: balancing the resource-heavy needs of the tech sector against community sustainability and energy security."
title: "From Indiana to Idaho, a Backlash Against A.I. Gathers Momentum"
uri: "https://www.nytimes.com/2026/04/27/technology/ai-artificial-intelligence-backlash.html"
4 changes: 4 additions & 0 deletions proofs/nyt/ai-backlash/supports/idahonews.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
claimUriDigest: "a6aa62d59056d0f6b74c26c26c3a8c561f6ec43320626443d2759bc771181464"
supportsClaim: true
reviewedBy: "semmet95"
uri: "https://idahonews.com/news/nation-world/ai-data-centers-spark-local-backlash-across-the-us-artificial-intelligence-electricity-utilities-noise-land-use-tax-incentives"
69 changes: 56 additions & 13 deletions scripts/post_requests.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import urllib.error
import urllib.request
from pathlib import Path
import traceback

# Shared utilities (try package import first, fallback to local module)
try:
Expand Down Expand Up @@ -61,58 +62,100 @@ def post(url: str, data: dict, api_key: str) -> tuple[int, str]:


def main() -> int:
def _info(msg: str, *args) -> None:
print("INFO:", msg % args if args else msg)

def _error(msg: str, *args) -> None:
print("ERROR:", msg % args if args else msg, file=sys.stderr)

def _exception(msg: str, *args) -> None:
print("ERROR:", msg % args if args else msg, file=sys.stderr)
traceback.print_exc(file=sys.stderr)

base_url = os.environ.get("API_BASE_URL", "").rstrip("/")
api_key = os.environ.get("API_KEY", "")

if not base_url:
print("API_BASE_URL environment variable is not set", file=sys.stderr)
_error("API_BASE_URL environment variable is not set")
return 1
if not api_key:
print("API_KEY environment variable is not set", file=sys.stderr)
_error("API_KEY environment variable is not set")
return 1

files = [f for f in os.environ.get("ADDED_FILES", "").splitlines() if f.strip()]
if not files:
print("No added files to process.")
_info("No added files to process.")
return 0

_info("POST run: %d file(s) to process", len(files))

spec = load_oapi("oapi.yaml")
schema_paths = extract_post_paths(spec)

failed = False
allowed_exts = {".yaml", ".yml", ".json"}
for f in files:
f = f.strip()
parts = Path(f).parts
if not parts or parts[0] not in SCHEMA_MAP:
if not f:
continue

# normalize path parts (skip '.' and '..')
p = Path(f)
parts = [part for part in p.parts if part not in (".", "..")]
if not parts:
continue

folder = parts[0]
if folder not in SCHEMA_MAP:
continue

norm_path = Path(*parts)
if norm_path.suffix.lower() not in allowed_exts:
_info("Skipping non-document file: %s", str(norm_path))
continue

schema_name = SCHEMA_MAP[folder]
path = schema_paths.get(schema_name)
if not path:
print(f"No POST path found for schema {schema_name}, skipping {f}")
_error("No POST path found for schema %s, skipping %s", schema_name, str(norm_path))
failed = True
continue

url = f"{base_url}{path}"
# warn if BASE_URL likely duplicates path prefix (common misconfiguration)
path_segments = [seg for seg in path.split("/") if seg]
if path_segments and base_url.rstrip("/").endswith("/" + path_segments[0]):
_info("Warning: BASE_URL '%s' may duplicate path segment '%s' when combined with '%s'", base_url, path_segments[0], path)

if not norm_path.exists():
_error("%s: File not found", str(norm_path))
failed = True
continue

try:
data = load_doc(str(norm_path))
except Exception as e:
_exception("%s: Failed to parse: %s", str(norm_path), e)
failed = True
continue

if not Path(f).exists():
print(f"{f}: File not found")
if not isinstance(data, dict):
_error("%s: Parsed document is not a JSON object; skipping", str(norm_path))
failed = True
continue

_info("Posting %s -> %s", str(norm_path), url)
try:
data = load_doc(f)
status, body = post(url, data, api_key)
except Exception as e:
print(f"{f}: Failed to parse: {e}")
_exception("%s: Request failed: %s", str(norm_path), e)
failed = True
continue

status, body = post(url, data, api_key)
if 200 <= status < 300:
print(f"{f}{url} ({status})")
_info("%s%s (%d)", str(norm_path), url, status)
else:
print(f"{f}{url} ({status}): {body[:200]}")
_error("%s%s (%d): %s", str(norm_path), url, status, body[:200])
failed = True

return 1 if failed else 0
Expand Down
40 changes: 31 additions & 9 deletions scripts/validate.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
#!/usr/bin/env python3
"""Validate request documents against OpenAPI schemas."""

import json
import sys
import os
from pathlib import Path
import traceback
from referencing.jsonschema import DRAFT202012
from referencing import Registry, Resource

# Shared utilities (try package import first, fallback to local module)
try:
Expand Down Expand Up @@ -32,7 +34,10 @@ def resolve_schema(spec: dict, ref: str) -> dict:
return current

def validate(data: dict, schema: dict, spec: dict) -> list[str]:
registry = Registry().with_resource("oapi", Resource.from_contents(spec)) # type: ignore
registry = Registry().with_resource(
"oapi",
Resource.from_contents(spec, DRAFT202012) # explicit spec
)
validator = Draft202012Validator(schema, registry=registry)
return [f"{e.json_path}: {e.message}" for e in validator.iter_errors(data)]

Expand All @@ -45,21 +50,38 @@ def scan_tracked_files() -> list[str]:
files.extend(Path(folder).rglob(ext))
return [str(f) for f in sorted(files)]


def _info(msg: str, *args) -> None:
print("INFO:", msg % args if args else msg)


def _error(msg: str, *args) -> None:
print("ERROR:", msg % args if args else msg, file=sys.stderr)


def _exception(msg: str, *args) -> None:
print("ERROR:", msg % args if args else msg, file=sys.stderr)
traceback.print_exc(file=sys.stderr)

def main() -> int:
files = sys.argv[1:]

if not files:
print("Validating all files...")
_info("Validating new docs...")
files = scan_tracked_files()
return 0

spec = load_oapi("oapi.yaml")
failed = False

_info("Validation run: %d file(s) to check", len(files))

for f in files:
f = f.strip()
if not f:
continue

_info("Validating %s", f)

parts = Path(f).parts
if not parts or parts[0] not in SCHEMA_MAP:
continue
Expand All @@ -69,25 +91,25 @@ def main() -> int:
schema = resolve_schema(spec, schema_ref)

if not Path(f).exists():
print(f"{f}: File not found")
_error("%s: File not found", f)
failed = True
continue

try:
data = load_doc(f)
except Exception as e:
print(f"{f}: Failed to parse document: {e}")
_exception("%s: Failed to parse document: %s", f, e)
failed = True
continue

errors = validate(data, schema, spec)
if errors:
print(f"{f}:")
_error("%s: %d validation error(s)", f, len(errors))
for e in errors:
print(f" - {e}")
_error(" - %s", e)
failed = True
else:
print(f"{f}")
_info("%s: OK", f)

return 1 if failed else 0

Expand Down
4 changes: 4 additions & 0 deletions sources/nyt.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
name: "The New York Times"
summary: "The New York Times is dedicated to helping people understand and engage with the world through on-the-ground, expert and deeply reported independent journalism."
tags: "american"
uri: "https://www.nytimes.com"
Loading