Skip to content

Add the Python API over grund-core and prove binding parity - #480

Merged
vjovanov merged 5 commits into
agent-grounds:mainfrom
vjovanov:fix/issue-470
Oct 6, 2026
Merged

vjovanov merged 5 commits into
agent-grounds:mainfrom
vjovanov:fix/issue-470

Conversation

@vjovanov

@vjovanov vjovanov commented Oct 6, 2026 •

Copy link
Copy Markdown
Collaborator

Closes #470

Before this change, the checkout had no Python frontend: import grund failed with ModuleNotFoundError. After a local install with CPython 3.10+ and Rust (python -m pip install . from the checkout), an application can check a tree, iterate its findings and read a declaration:

from grund import check, show

repo = "tests/e2e/cases/json-report/repo"
result = check(repo)
for finding in result.report:
    print(finding.code, finding.line)  # dangling 3
assert "FS-999-missing" in show("FS-001-alpha", root=repo, mode="brief").body

The output above comes from the caller's print; the API itself is silent. The Python guide and runnable example use this fixture.

The complete initial disk-backed inventory includes check/selectors and report iteration, scan, single/batch show, refs, ID lists and sizes, coverage/text, formatting, ID proposal, init, effective configuration and validation, fetch, managed integrations, ID completion, reference style and agent setup instructions. Required operands are positional and other options are keywords with documented defaults. Process transport, watch/exit lifecycle and LSP editor utilities retain their stated frontend scope. §FS-distribution.3.3.5

Results are frozen dataclasses with tuple collections and explicit None for optional fields; effective configuration is recursively read-only. CheckResult keeps both the complete report and selected_report, plus separate run_cautions. Findings preserve locations, all sites, suggestions and rule authority. A completed check with findings returns normally. §FS-distribution.3.3.1

Operations that cannot run raise ConfigError, FilesystemError, QueryError or fallback OperationError, each carrying a structured .failure with causes, details, cautions and partial output. Single query failures raise; batch queries retain individual failures in ordered records. Fetch execution, snapshot writes and snapshot traversal retain filesystem locations and original I/O causes. The final conversion fix extracts OS error codes from the retained source chain, without parsing messages or synthesizing codes. §FS-distribution.3.3.2

Each call resolves its own root; omitted roots snapshot cwd and explicit paths preserve engine scope, including filesystem-significant symlink/... Inputs accept str and os.PathLike[str], reject bytes, surrogates and NUL as documented, and retain logical report paths with /. A core preflight rejects the known unsafe unnamed non-Unicode workspace alias. §FS-distribution.3.3.3 Calls are synchronous, release the GIL during Rust work, read no process argv, change no global cwd and never exit Python. Independent reads may overlap; callers serialize writers. Interrupts are checked on return, so work may finish before KeyboardInterrupt; there is no async or mid-call cancellation promise. §FS-distribution.3.3.4

Mutation requires explicit opt-in: fmt() and init() preview by default, init(check=True) suppresses writes, and fetch(..., write=True) authorizes materialization. Fetch without opt-in refuses before config loading or fetcher execution. Integration writes reuse managed ownership, preference validation and agent gates, preserving manual text and instructions. Existing engine data-preservation contracts and CLI defaults remain intact. §FS-distribution.3.3.6

crates/grund-py is an independent PyO3 frontend over grund-core. Python owns conversion and exception policy; additive core adapters own warning/failure propagation, queries, path preflight and integration orchestration. It uses no CLI subprocess or frontend dependency and duplicates no parser, scanner, resolver or rules. Existing supported Rust entry points and CLI output remain compatible. §FS-distribution.3.1, §AR-bindings.6

Root pyproject.toml uses maturin to build the private grund._native extension with abi3-py310. The public python/grund package supplies annotated signatures, types and py.typed; source inclusion supports clean-checkout and unpacked-sdist installs. Ordinary Cargo CLI builds need no Python build dependencies. This handoff targets CPython 3.10+ with the GIL; PyPy and free-threaded Python are unsupported. It adds no competing console entrypoint. §FS-distribution.3.3.7

The shared corpus and core-only Rust oracle prove Rust/Python parity through separate complete-data and exact canonical UTF-8 JSON assertions. They cover ordering, nulls, escaping, Unicode/logical paths, warnings, suggestions, sites and authority, alongside mutation preview/write/refusal bytes. Frozen CLI stdout/stderr projections remain checked against authoritative existing goldens, including null-line findings on stderr and the existing empty-stream fixture convention. Node joins through #469. §FS-distribution.3.0.3, §AR-goal-measurement.2

Verification at bba278fc068ff8594e39dd29ddf3f29a8cac9a8b:

  • A fresh local wheel build/install and cargo build --locked -p grund-core --example grund-binding-oracle --target-dir target passed.
  • python tests/bindings/run.py passed all 33 tests in 103.158s. Coverage includes clean-checkout/unpacked-sdist installs, actual signatures/types/examples, complete-data/canonical-byte parity, CLI JSON goldens, mutation bytes, root independence, silence, GIL/interrupt behavior and resolved frontend isolation. Missing-executable, symlink-parent, denied snapshot-write and denied snapshot-traversal regressions all passed; both permission tests ran as an unprivileged POSIX user.
  • env TMPDIR=/dev/shm pre-commit run --all-files passed all ten hooks, including the warnings-as-errors build, Rust/Python tests, grounding, formatting, managed init, links and file-size budgets. The final three-command local gate took 8m42s.
  • Both review rounds' findings, R1-01 through R1-06 and R2-01, are fixed; none is rejected or deferred. Hosted CI and merge remain for shipping.

PyPI publication remains pending. #471 consumes the source/build/type handoff and owns the release matrix, CLI payload, assembly and publication. This change performs no upload, tag, release dispatch or release and assigns no milestone or additional 1.0 gate. Carry Adapt Python marshalling to #466/#453/#454, replacing internal adapters while preserving the approved Python schema and rerunning parity. These coordination items are not landing prerequisites. §FS-distribution.3.1, §FS-distribution.3.3.7

AI workflow: `rhei`, 24 agent invocations across 1 model; 12 tasks completed, 4 in progress.
  1. github-issues-agent-grounds-grund-470-implement-379c3f6c.ticket supervising (visit 1) — cdx, openai/gpt-6.1-sol — 1m27s — 373.4k in / 3.5k out
  2. github-issues-agent-grounds-grund-470-implement-379c3f6c.ticket.triage assessing (visit 1) — cdx, openai/gpt-6.1-sol — 1m31s — 331.8k in / 3.4k out
  3. github-issues-agent-grounds-grund-470-implement-379c3f6c.ticket.triage fitting (visit 1) — cdx, openai/gpt-6.1-sol — 6m55s — 1.7M in / 18.2k out
  4. github-issues-agent-grounds-grund-470-implement-379c3f6c.ticket supervising (visit 2) — cdx, openai/gpt-6.1-sol — 2m13s — 658.6k in / 5.0k out
  5. github-issues-agent-grounds-grund-470-implement-379c3f6c.ticket.clarify clarifying — cdx, openai/gpt-6.1-sol — 2m25s — 749.3k in / 5.8k out
  6. github-issues-agent-grounds-grund-470-implement-379c3f6c.ticket supervising (visit 3) — cdx, openai/gpt-6.1-sol — 1m26s — 350.3k in / 3.8k out
  7. github-issues-agent-grounds-grund-470-implement-379c3f6c.ticket.plan planning — cdx, openai/gpt-6.1-sol — 11m05s — 3.3M in / 25.8k out
  8. github-issues-agent-grounds-grund-470-implement-379c3f6c.ticket supervising (visit 4) — cdx, openai/gpt-6.1-sol — 1m09s — 479.1k in / 2.7k out
  9. github-issues-agent-grounds-grund-470-implement-379c3f6c.ticket supervising (visit 5) — cdx, openai/gpt-6.1-sol — 1m33s — 420.5k in / 4.1k out
  10. github-issues-agent-grounds-grund-470-implement-379c3f6c.ticket.specify specify — cdx, openai/gpt-6.1-sol — 24m35s — 7.8M in / 58.5k out
  11. github-issues-agent-grounds-grund-470-implement-379c3f6c.ticket supervising (visit 6) — cdx, openai/gpt-6.1-sol — 2m06s — 708.6k in / 5.4k out
  12. github-issues-agent-grounds-grund-470-implement-379c3f6c.ticket.implement implement — cdx, openai/gpt-6.1-sol — 36m06s — 12.2M in / 84.4k out
  13. github-issues-agent-grounds-grund-470-implement-379c3f6c.ticket supervising (visit 7) — cdx, openai/gpt-6.1-sol — 1m40s — 602.0k in / 4.2k out
  14. github-issues-agent-grounds-grund-470-implement-379c3f6c.ticket.review-1 review — cdx, openai/gpt-6.1-sol — 7m19s — 3.5M in / 17.0k out
  15. github-issues-agent-grounds-grund-470-implement-379c3f6c.ticket supervising (visit 8) — cdx, openai/gpt-6.1-sol — 1m53s — 592.9k in / 4.9k out
  16. github-issues-agent-grounds-grund-470-implement-379c3f6c.ticket.fix-1 fix — cdx, openai/gpt-6.1-sol — 5m20s — 1.7M in / 13.4k out
  17. github-issues-agent-grounds-grund-470-implement-379c3f6c.ticket supervising (visit 9) — cdx, openai/gpt-6.1-sol — 1m47s — 625.2k in / 4.6k out
  18. github-issues-agent-grounds-grund-470-implement-379c3f6c.ticket.review-2 review — cdx, openai/gpt-6.1-sol — 4m18s — 1.6M in / 9.7k out
  19. github-issues-agent-grounds-grund-470-implement-379c3f6c.ticket supervising (visit 10) — cdx, openai/gpt-6.1-sol — 1m56s — 848.9k in / 4.8k out
  20. github-issues-agent-grounds-grund-470-implement-379c3f6c.ticket.fix-2 fix — cdx, openai/gpt-6.1-sol — 7m53s — 1.6M in / 20.5k out
  21. github-issues-agent-grounds-grund-470-implement-379c3f6c.ticket supervising (visit 11) — cdx, openai/gpt-6.1-sol — 2m03s — 775.2k in / 4.9k out
  22. github-issues-agent-grounds-grund-470-implement-379c3f6c.ticket.green green-fix (visit 1) — cdx, openai/gpt-6.1-sol — 3m23s — 1.5M in / 7.8k out
  23. github-issues-agent-grounds-grund-470-implement-379c3f6c.ticket.green green-fix (visit 2) — cdx, openai/gpt-6.1-sol — 56.0s — 335.4k in / 1.5k out
  24. github-issues-agent-grounds-grund-470-implement-379c3f6c.ticket supervising (visit 12) — cdx, openai/gpt-6.1-sol — 2m07s — 680.5k in / 4.5k out
Accounting Value
cost $12.44
total tokens 43.9M
input tokens (incl. cache) 43.6M
input cache read 41.0M
input cache write -
output tokens (incl. cache) 318.4k
output cache read -
output cache write -
coverage Complete

@vjovanov vjovanov changed the title Specify the Python API and pin complete binding parity Add the Python API over grund-core and prove binding parity Oct 6, 2026
Retain fetch I/O sources and locations through the additive failure carrier (§FS-distribution.3.3.2), and preserve symlink/.. inputs for engine resolution (§FS-distribution.3.3.3).

Correct independent CLI stream and golden comparisons (§FS-distribution.3.0.3), maintain frontend isolation (§AR-bindings.1), and separate the discovery citation note (§FS-inline-citation-style.2.3.1). Add binding regressions for both behavior corrections.
Retain the original snapshot-folder traversal error and its embedded I/O source through the additive fetch diagnostic carrier (§FS-distribution.3.3.2). Preserve scanner records, refusal ordering, and CLI failure text, and retain the fallible walk source alongside its location.

Pin denied traversal with direct FilesystemError, location, original cause, OS-code, caution, canonical-parity, and restored-permission byte assertions. Move the unchanged reporting pass into its scanner sibling module to satisfy the staged file-size check. Behavioral verification remains with green.
@vjovanov
vjovanov marked this pull request as ready for review October 6, 2026 13:03
@vjovanov
vjovanov merged commit dbc2d00 into agent-grounds:main Oct 6, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add the PyO3 Python API over grund-core and prove binding parity

1 participant