Skip to content

fix: a registry the schema refuses is refused whole - #177

Merged
vjovanov merged 3 commits into
mainfrom
fix/issue-158
Oct 3, 2026
Merged

vjovanov merged 3 commits into
mainfrom
fix/issue-158

Conversation

@vjovanov

@vjovanov vjovanov commented Oct 3, 2026 •

Copy link
Copy Markdown
Collaborator

Closes #158

What changes for a caller

Take the issue's hand-written workspaces.json, which leaves out five required fields: the organization's name, the project's display_name, the project type's layout, and the type's agents.template and agents.structure_intro.

Before, ephor validate, ephor refresh and every other command that loads the registry named only the first one:

$ ephor validate --registry workspaces.json --schema-only
ERROR: Registry does not match schema at '/organizations/0': "name" is a required property

To get to a registry ephor accepts, you had to fix the named field and run again, five times.

After, one run names all five and points at the shipped example:

$ ephor validate --registry workspaces.json --schema-only
ERROR: Registry does not match schema (5 violations):
  /organizations/0: "name" is a required property
  /project_types/0/agents: "template" is a required property
  /project_types/0/agents: "structure_intro" is a required property
  /project_types/0: "layout" is a required property
  /projects/0: "display_name" is a required property
config/workspaces.example.json is a complete registry to start from.

The issue's reproducer used to need five failing refreshes. Now it needs one: the first refresh names 5 of 5 fields and the example, and the second is accepted.

What changed

  • A registry that fails its schema is refused whole. validate_registry (src/registry.rs) used to keep only validator.iter_errors(registry).next(). It now collects every violation the jsonschema crate yields in one schema pass. The message has three parts: a header that counts the violations (violation when there is one), one indented <instance_path>: <error> line per violation in the order the validator yields them, and a closing line that names config/workspaces.example.json as a complete registry to start from (§FS-006-project-interface.11.1). The closing line follows the precedent of the missing status config, whose error already says "Copy config/status.example.json there and edit it."
  • Nothing a caller parses changes. The error, its exit code and the --json shape are the same as before. Under --json the list is inside the existing says string, and there is no new field (§FS-006-project-interface.11.1). Every command that loads the registry (validate, validate --schema-only, refresh and the rest) goes through this one function, so they all give this one answer.
  • Spec, docs and changelog. The new point §FS-006-project-interface.11.1 states the rule, and the code cites it. docs/registry.md says the same next to its mention of the worked example. A changelog fragment, docs/changelog/unreleased/registry-refused-whole.fixed.md, records the fix.

Found and deliberately left alone

  • The checks after the schema still stop at their first failure (R1-03, adjacent). These are ensure_unique_ids, validate_hook_set, validate_project_type, validate_project, and the derived and required branch ids. They run only once the schema passes, and the issue's reproducer does not measure them. Collecting their failures is a separate refactor and belongs in its own ticket. The spec point says that this pass does not cover them.
  • A violation at the registry root has an empty path (R1-02, minor). Its line reads : <error> because the root's instance path is empty. The line is still readable and no worse than the old at '': wording, so it is left for later.
  • A flaky test met during the gate. e2e_009_jobs::a_held_lock_is_what_running_means failed once in code this change does not touch, then passed 5 of 5 on rerun. It is reported as a_held_lock_is_what_running_means fails intermittently on Linux: E2E-009-jobs.rs:169 #178.

How it was verified

  • The spec and the failing tests came first. They are in 3f73db2, before the fix (6a82a0b). At that commit the tests failed by naming only /organizations/0, which is the reported defect.
  • E2E-048 (tests/e2e/cases/E2E-048-a-registry-refused-whole.rs, new) is built from the issue's five-field registry. Its three cases assert that all five violations and the example pointer appear in one answer:
    • validate_names_every_violation_in_one_run
    • validate_json_carries_the_list_in_says
    • refresh_names_every_violation_in_one_run
  • The issue's reproducer (ephor.21) exits 0 at 6a82a0b: the first refresh names 5 of 5 fields and the example, and the second refresh is accepted.
  • The full gate is green on bfc145e:
    • pre-commit run --all-files: grund check and grund fmt with CI's pinned grund 0.14.0, fissile, private words, and attribution.
    • python -m unittest discover -s tests/integration -p 'test_*.py': 102 tests.
    • python scripts/check_boundary.py and python scripts/check_parity.py.
    • cargo test with TMPDIR pointed at a symlinked directory, as macOS CI has it.

The case is numbered E2E-048 because main already has E2E-045 to E2E-047.

AI workflow: `rhei`, 10 agent invocations across 1 model; 6 tasks completed, 10 in progress.
  1. github-issues-agent-grounds-ephor-158-implement-e2713ed7.ticket supervising (visit 1) — cld, anthropic/claude-opus-5-5 — 44.0s — 590.8k in / 3.9k out
  2. github-issues-agent-grounds-ephor-158-implement-e2713ed7.ticket supervising (visit 2) — cld, anthropic/claude-opus-5-5 — 1m09s — 550.3k in / 4.8k out
  3. github-issues-agent-grounds-ephor-158-implement-e2713ed7.ticket.specify specify — cld, anthropic/claude-opus-5-5 — 14m20s — 2.3M in / 12.0k out
  4. github-issues-agent-grounds-ephor-158-implement-e2713ed7.ticket supervising (visit 3) — cld, anthropic/claude-opus-5-5 — 22.0s — 206.9k in / 2.1k out
  5. github-issues-agent-grounds-ephor-158-implement-e2713ed7.ticket.implement implement — cld, anthropic/claude-opus-5-5 — 2m34s — 890.4k in / 5.7k out
  6. github-issues-agent-grounds-ephor-158-implement-e2713ed7.ticket supervising (visit 4) — cld, anthropic/claude-opus-5-5 — 35.0s — 212.1k in / 2.2k out
  7. github-issues-agent-grounds-ephor-158-implement-e2713ed7.ticket.review-1 review — cld, anthropic/claude-opus-5-5 — 3m25s — 1.1M in / 8.5k out
  8. github-issues-agent-grounds-ephor-158-implement-e2713ed7.ticket supervising (visit 5) — cld, anthropic/claude-opus-5-5 — 43.0s — 295.4k in / 2.8k out
  9. github-issues-agent-grounds-ephor-158-implement-e2713ed7.ticket.green green-fix — cld, anthropic/claude-opus-5-5 — 3m11s — 688.8k in / 4.1k out
  10. github-issues-agent-grounds-ephor-158-implement-e2713ed7.ticket supervising (visit 6) — cld, anthropic/claude-opus-5-5 — 24.0s — 233.1k in / 2.2k out
Accounting Value
cost $5.41
total tokens 7.2M
input tokens (incl. cache) 7.1M
input cache read 6.5M
input cache write 629.5k
output tokens (incl. cache) 48.4k
output cache read -
output cache write -
coverage Complete

A registry that fails its schema is answered with every violation one
schema pass sees, each at its instance path, counted, and closed with a
pointer at config/workspaces.example.json (FS-006-project-interface.11.1).
E2E-045 holds validate, validate --schema-only, validate --json and
refresh to it with the hand-written registry from #158, which owes five
required fields; today each names only the first.
validate_registry kept only the first item of iter_errors. It now lists
every violation one schema pass sees, one line each under a header that
counts them, and closes by naming config/workspaces.example.json.
@vjovanov vjovanov changed the title spec: a registry the schema refuses is refused whole fix: a registry the schema refuses is refused whole Oct 3, 2026
@vjovanov
vjovanov marked this pull request as ready for review October 3, 2026 10:12
@vjovanov
vjovanov merged commit 0dd19de into main Oct 3, 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.

Registry validation reports only the first schema violation, so a registry missing N fields takes N edit-and-rerun cycles

1 participant