Skip to content

Support block-form nesting and unquoted assertions; compile doc examples in CI - #10

Merged
rokoss21 merged 1 commit into
masterfrom
fix/block-syntax-and-doc-checks
Aug 21, 2026
Merged

Support block-form nesting and unquoted assertions; compile doc examples in CI#10
rokoss21 merged 1 commit into
masterfrom
fix/block-syntax-and-doc-checks

Conversation

@rokoss21

Copy link
Copy Markdown
Owner

Follow-up to #9. I compiled every ```facet block in the documentation of both repositories — 43 blocks — and two more documented constructs turned out never to have been implemented.

Block-form nesting (§5.1–§5.2)

Facet bodies accepted only inline literals, so a key followed by an indented map or list failed with F003. That is how the specification prints its own @context minimal schema:

@context
  budget: 32000
  defaults:
    priority: 500
    min: 0

…and how docs/02-tutorial.md writes @policy rule lists. Neither compiled.

block_body now parses a nested block when a key carries no inline value, and a list item may itself be a block map (- id: ... with further pairs indented beneath). Verified equivalence: block and inline spellings produce the same AST, and an equivalent policy yields an identical policy_hash (sha256:7397fb8c… both ways) while document_hash differs as it should.

Unquoted @test assertions (§15.1)

The spec writes assertions as bare expressions, but the parser demanded a quoted string, so §15.1's own example failed:

@test "basic"
  assert:
    - canonical contains "hello"

assert: items are now read as raw lines. Quoted items still work, so examples/spec/08_test_suite.facet and any existing document are unaffected. A false assertion still fails the test — this is not a blanket "accept everything".

Keeping docs conformant

scripts/check_doc_examples.py builds every fenced facet block with the reference compiler, wired into CI as Doc Examples Compile. Blocks that are meant not to compile — negative examples, syntax fragments, imports of paths that do not exist — live in scripts/doc_examples_allowlist.json with a reason, keyed by content hash so entries survive a block moving within a file. An allowlisted block that starts compiling is reported as stale, so the list cannot rot. Verified both directions: an intentionally wrong entry is caught.

This is the guard for the class of problem that started this whole thread: documentation that teaches syntax the compiler rejects is what newcomers and LLM assistants copy first.

Also fixed

  • docs/02-tutorial.md: the @policy example omitted name, which §16.2.2 requires for tool_* rules — the documented policy raised F452. (Found only after the parser stopped failing first.)
  • CHANGELOG.md carried a second, duplicated copy of the v2.0 changelog.

Verification

  • 484 workspace tests pass, 8 new in tests/spec_conformance_regressions.rs, including equality of block vs inline ASTs, equality of quoted vs unquoted assertions, and that a dangling key: is still an error
  • smoke + spec matrix suites green; doc-example check green over 43 blocks (13 allowlisted)
  • cargo fmt --all -- --check and cargo clippy --all-targets --all-features -- -D warnings clean

🤖 Generated with Claude Code

…s in CI

Compiling every ```facet block in the documentation turned up two more
constructs the spec documents but the parser never accepted.

Block-form nesting (§5.1–§5.2). Facet bodies only accepted inline
literals, so a key followed by an indented map or list failed with
`F003`. That is how the specification prints its own `@context` minimal
schema (§12.2) and how docs/02-tutorial.md writes `@policy` rule lists —
neither compiled. `block_body` now parses a nested block when a key has
no inline value, and a list item may be a block map (`- id: ...` with
further pairs indented under it). Inline and block spellings produce the
same AST, and the same `policy_hash` for an equivalent policy.

Unquoted `@test` assertions (§15.1). The specification writes assertions
as bare expressions (`- canonical contains "hello"`), but the parser
required a quoted string, so §15.1's own example failed. `assert:` items
are now read as raw lines; quoted items are still accepted so existing
documents (including examples/spec/08_test_suite.facet) are unaffected.

To keep documentation from drifting back out of conformance,
scripts/check_doc_examples.py builds every fenced facet block with the
reference compiler, and a new CI job runs it. Blocks that are meant not
to compile — negative examples, syntax fragments, imports of paths that
do not exist — are listed in scripts/doc_examples_allowlist.json with a
reason, keyed by content hash so an entry survives the block moving. An
allowlisted block that starts compiling is reported as stale, so the
list cannot rot.

Also fixed while here:
- docs/02-tutorial.md's `@policy` example omitted `name`, which §16.2.2
  requires for `tool_*` rules, so the documented policy raised `F452`.
- CHANGELOG.md carried a second, duplicated copy of the v2.0 changelog.

Verified: 484 workspace tests pass (8 new), smoke and matrix suites
green, doc-example check green over 43 blocks (13 allowlisted), fmt
clean, clippy -D warnings clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@rokoss21
rokoss21 merged commit 3ad9fb7 into master Aug 21, 2026
13 checks passed
@rokoss21
rokoss21 deleted the fix/block-syntax-and-doc-checks branch August 21, 2026 21:47
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.

1 participant