Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
223f63b
docs: start v0.6.0 WP-0 baseline
Jul 30, 2026
58e0902
feat: implement WP-1 grounding JSON validation
Jul 30, 2026
6b72bc0
feat: add Grounding JSON CLI loading
Jul 30, 2026
a615f45
test: cover Grounding JSON source binding
Jul 30, 2026
9474d58
fix: tighten Grounding JSON source validation
Jul 30, 2026
aae02aa
feat: stabilize Grounding JSON validation errors
Jul 30, 2026
567a28d
test: cover Grounding JSON error vocabulary
Jul 30, 2026
f43a68d
feat: start npm Grounding SDK
Jul 30, 2026
526cdc2
feat: add npm Grounding mapper examples
Jul 30, 2026
db5616a
test: harden npm Grounding SDK acceptance
Jul 30, 2026
6a38229
test: prove Grounding representation staleness
Jul 30, 2026
0f8c254
test: cover npm SDK process boundaries
Jul 30, 2026
c7a9617
test: cover npm SDK artifact cleanup
Jul 30, 2026
c79fda9
test: verify packaged Grounding fixture integrity
Jul 30, 2026
704a345
docs: add Grounding correction quickstart
Jul 30, 2026
3a0f9a3
fix: reject vendor binaries without grounding
Jul 30, 2026
33f2088
fix: complete WP-2 dispatch and stop punishing correct PDFium setup
docushell-dev Jul 30, 2026
f3a76c6
fix: give the npm SDK a typed unsupported-platform failure
docushell-dev Jul 30, 2026
3b6abea
build: repair contract gates left dangling by the roadmap.md removal
docushell-dev Jul 30, 2026
0ea444f
docs: add the v0.6.0 release record, mapper guide, and governance upd…
docushell-dev Jul 30, 2026
1022294
build: refresh the npm scaffold gate to the published v0.5.0 payload
docushell-dev Jul 30, 2026
9d01148
docs: record the clean-room walkthrough and the public-version deadlock
docushell-dev Jul 30, 2026
d04385f
docs: rule fingerprint identity and advance install wording to publis…
docushell-dev Jul 30, 2026
ad4f01e
fix: cut unrecorded source binding from verify and verify-batch
docushell-dev Jul 30, 2026
52b365e
build: make governance that nobody runs impossible
docushell-dev Jul 30, 2026
f145c25
test: cover emoji and combining-mark offset vectors
docushell-dev Jul 30, 2026
a6a702a
fix: drop sourceArtifactPath from the VerifyClaimsOptions generator
docushell-dev Jul 30, 2026
5d480a9
docs: record DocuShell acceptance and validator resource baseline
docushell-dev Jul 31, 2026
49fa1cd
docs: bind DocuShell acceptance to reviewed main commit cc652ec
docushell-dev Jul 31, 2026
2f8695c
docs: measure the validator at the frozen ceiling instead of extrapol…
docushell-dev Jul 31, 2026
84fcfb4
perf: accept the validator resource ceiling and enforce it
docushell-dev Jul 31, 2026
39489e4
build: activate v0.6.0 core version and request its public wording
docushell-dev Jul 31, 2026
f0d9198
docs: approve the v0.6.0 public wording with a revision clause
docushell-dev Jul 31, 2026
24826d8
perf: index the Grounding JSON validator and cover the shape that was…
docushell-dev Jul 31, 2026
804b448
fix: keep report writes atomic without destroying non-regular destina…
docushell-dev Jul 31, 2026
bd943af
docs: correct the crate map and clarify two contract descriptions
docushell-dev Jul 31, 2026
0023ae4
fix(ethos-pdf): apply page rotation when mapping PDFium text coordinates
docushell-dev Aug 2, 2026
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
4 changes: 2 additions & 2 deletions .github/scripts/check_verify_dependency_boundary.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,8 @@ def main() -> None:
dependencies = ", ".join(sorted(ALLOWED_NORMAL_DEPENDENCIES))
features = ", ".join(sorted(ETHOS_CORE_FEATURES))
print(
f"ok: {PACKAGE_NAME} normal dependencies are [{dependencies}]; "
f"ethos-core default features are disabled and features are [{features}]"
f"ok: {PACKAGE_NAME} manifest normal dependencies are [{dependencies}]; "
f"ethos-core default features are disabled and features are [{features}] (manifest check only)"
)


Expand Down
199 changes: 0 additions & 199 deletions .github/scripts/test_app_answer_release_release_prep.py

This file was deleted.

2 changes: 0 additions & 2 deletions .github/scripts/test_evidence_anchor_v1_contract.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@
REPORT_SCHEMA = ROOT / "schemas/ethos-evidence-anchor-report.schema.json"
SCHEMAS_README = ROOT / "schemas/README.md"
VALIDATE_EXAMPLES = ROOT / "schemas/validate_examples.py"
ROADMAP = ROOT / "docs/roadmap.md"
EXECUTION_STATUS = ROOT / "docs/execution-status.md"
README = ROOT / "README.md"
EVIDENCE_TYPES = ROOT / "crates/ethos-core/src/evidence_anchor.rs"
Expand All @@ -46,7 +45,6 @@
"cargo test --locked -p ethos-grounding-opendataloader-json",
"$(PYTHON) schemas/validate_examples.py",
"$(PYTHON) .github/scripts/test_execution_status.py",
"$(PYTHON) .github/scripts/test_roadmap_status.py",
"$(PYTHON) .github/scripts/test_evidence_anchor_v1_contract.py",
"git diff --check",
]
Expand Down
16 changes: 8 additions & 8 deletions .github/scripts/test_execution_status.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,18 +34,18 @@ def test_status_is_scoped_to_internal_continuation(self) -> None:
text = status_text()

self.assertIn(
"Status: v0.4.0 Rust library crates `ethos-doc-core`, `ethos-verify`, and `ethos-pdf` "
"Status: v0.5.0 Rust library crates `ethos-doc-core`, `ethos-verify`, and `ethos-pdf` "
"are live on crates.io, and the Python `ethos-pdf` wheel is live on PyPI.",
text,
)
self.assertIn(
"The exact v0.4.0 public install wording packet is approved and closed out",
"The exact v0.5.0 public install wording packet is approved and closed out",
text,
)
self.assertIn("docs/validation/v0-3-0-public-install-wording-approval-decision-validation-2026-07-02.md", text)
self.assertIn("docs/validation/v0-3-0-public-install-wording-closeout-validation-2026-07-02.md", text)
self.assertIn("GitHub Release `v0.3.0`", text)
self.assertIn("npm `@docushell/ethos-pdf@0.4.0` is live on npm", text)
self.assertIn("npm `@docushell/ethos-pdf@0.5.0` is live on npm", text)
self.assertIn("v0.3.0 npm publication closeout", text)
self.assertIn("DocuShell integration remain blocked", text)
self.assertIn("Internal Milestone D source-only closeout remains complete", text)
Expand Down Expand Up @@ -106,15 +106,15 @@ def test_public_posture_boundary_remains_explicit(self) -> None:
text,
)
self.assertIn(
"v0.4.0 Rust library crates `ethos-doc-core`, `ethos-verify`, and `ethos-pdf` are live on crates.io",
"v0.5.0 Rust library crates `ethos-doc-core`, `ethos-verify`, and `ethos-pdf` are live on crates.io",
text,
)
self.assertIn("the Python `ethos-pdf` wheel is live on PyPI", text)
self.assertIn("npm `@docushell/ethos-pdf@0.4.0` is live on npm", text)
self.assertIn("The exact v0.4.0 public install wording packet is approved and closed out", text)
self.assertIn("GitHub Release `v0.4.0`", text)
self.assertIn("npm `@docushell/ethos-pdf@0.5.0` is live on npm", text)
self.assertIn("The exact v0.5.0 public install wording packet is approved and closed out", text)
self.assertIn("GitHub Release `v0.5.0`", text)
self.assertIn("macOS arm64/Linux x64 CLI artifacts", text)
self.assertIn("`@docushell/ethos-pdf@0.4.0`", text)
self.assertIn("`@docushell/ethos-pdf@0.5.0`", text)
self.assertIn("docs/validation/v0-3-0-publication-closeout-validation-2026-07-01.md", text)
self.assertIn("ethos-doc-core", text)
self.assertIn("ethos-verify", text)
Expand Down
118 changes: 118 additions & 0 deletions .github/scripts/test_gate_reachability.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
#!/usr/bin/env python3
#
# Copyright 2026 The Ethos maintainers
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
"""Structural guard: governance that nobody executes is not governance.

Two failure modes had gone unnoticed for months before this gate existed:

- 15 gate scripts were unreachable from CI. They ran only from a `make` target, so when
`docs/roadmap.md` was deleted as a completed historical record, the eight contract gates
asserting it still existed simply went red and stayed red.
- Seven `make` targets referenced roughly 280 scripts that had been deleted, including
`test_roadmap_status.py` in eleven places. Those targets could not run at all, which is
precisely why nobody noticed the gates behind them were broken.

A red gate nobody runs is worse than no gate: it costs real time whenever someone finally
runs it, and it trains readers to ignore failures. This file makes both states impossible.
"""

from __future__ import annotations

import re
import unittest
from pathlib import Path


ROOT = Path(__file__).resolve().parents[2]
SCRIPTS = ROOT / ".github/scripts"
WORKFLOWS = ROOT / ".github/workflows"
MAKEFILE = ROOT / "Makefile"
SCRIPT_REF = re.compile(r"\.github/scripts/([a-z0-9_]+\.py)")

# This module is itself invoked by name from the governance-gates job.
SELF = "test_gate_reachability.py"


def workflow_text() -> str:
return "\n".join(p.read_text(encoding="utf-8") for p in sorted(WORKFLOWS.glob("*.yml")))


def makefile_blocks() -> dict[str, list[str]]:
blocks: dict[str, list[str]] = {}
current: str | None = None
for line in MAKEFILE.read_text(encoding="utf-8").splitlines():
header = re.match(r"^([a-zA-Z][a-zA-Z0-9._-]*):", line)
if header:
current = header.group(1)
blocks[current] = []
elif current and line.startswith("\t"):
blocks[current].append(line)
return blocks


def gates() -> set[str]:
return {p.name for p in SCRIPTS.glob("test_*.py")}


def ci_reachable() -> set[str]:
"""Gate scripts CI executes, named directly or via a `make` target CI runs."""
text = workflow_text()
reachable = set(re.findall(r"(test_[a-z0-9_]+)\.py", text))
reachable = {f"{name}.py" for name in reachable}
blocks = makefile_blocks()
for target in set(re.findall(r"make ([a-z0-9][a-z0-9-]*)", text)):
for line in blocks.get(target, []):
reachable.update(SCRIPT_REF.findall(line))
return reachable


class GateReachabilityTests(unittest.TestCase):
def test_every_gate_script_is_reachable_from_ci(self) -> None:
orphans = sorted(gates() - ci_reachable() - {SELF})

self.assertEqual(
[],
orphans,
"these gate scripts are never executed by CI. Either wire each into a workflow "
"(directly or through a `make` target CI runs) or delete it. An unrun gate rots "
f"silently and blocks whoever runs it next: {orphans}",
)

def test_makefile_only_references_scripts_that_exist(self) -> None:
missing: dict[str, set[str]] = {}
for target, lines in makefile_blocks().items():
for line in lines:
for script in SCRIPT_REF.findall(line):
if not (SCRIPTS / script).is_file():
missing.setdefault(target, set()).add(script)

self.assertEqual(
{},
{t: sorted(s) for t, s in missing.items()},
"these `make` targets invoke scripts that do not exist, so the target cannot run. "
"Remove the target if its release or milestone has shipped.",
)

def test_workflows_only_reference_scripts_that_exist(self) -> None:
missing = sorted(
{s for s in SCRIPT_REF.findall(workflow_text()) if not (SCRIPTS / s).is_file()}
)

self.assertEqual([], missing, f"workflows reference missing gate scripts: {missing}")


if __name__ == "__main__":
unittest.main(verbosity=2)
Loading
Loading