Fix five spec-conformance defects (parser, @input types, layout min, json() lens, CLI stdout) - #9
Merged
Merged
Conversation
Each of these makes a documented, spec-required construct unusable.
Parser: a comment line with an empty body (a bare `#`) failed the whole
document with `F003: Unclosed delimiter`, pointing at offset 0 rather
than the offending line. Appendix B defines the comment body as
zero-or-more characters, so `is_not` is one repetition too strict.
Runtime inputs: `@input` validated only primitives and `any`. Every
composite FTS type — `list<T>`, `map<string, T>`, `struct { ... }`,
unions, multimodal assets — failed with `F453` even for conforming
values, which makes structured state impossible to hand to a contract.
Validation now goes through the type system that already exists: the
new `fct_validator::runtime_value_matches_type` parses the declared FTS
type expression and matches the value against it. `int` is still
widened to `float` per §8.4.
Token Box Model: a `min` larger than the section's own content left the
section neither truncatable (already below min) nor droppable (the drop
test required `size == min`), so the layout silently exceeded the
budget — 150 units rendered against a budget of 120 in the added test.
`min` is now clamped to the section size before both decisions, which
is what §11.3 means by a floor on retained content. The spec's own
wording does not cover `size < min`; the clamp is the reading that
keeps the resource bound.
`json()` lens: serialized `ValueNode` directly, leaking the internal
tagged representation (`{"kind":"Map","value":{...}}`) into rendered
content, and treated `indent` as a positional argument only, so the
documented `json(indent=2)` was silently ignored. It now emits plain
JSON per Appendix A, honours `indent` in both forms, and rejects
unevaluated nodes explicitly.
CLI: `tracing` wrote INFO diagnostics to stdout, mixed into the
Canonical JSON that `run --format json` emits, with ANSI escapes even
when piped — so the integration pattern documented in
docs/18-integration-guide.md could not be piped to `jq` (and
scripts/spec_matrix_examples.sh had to strip logs to work). Logs now go
to stderr, colour is gated on `stderr().is_terminal()`, and `--verbose`
no longer installs a second global subscriber. The startup line also
reported the host default budget instead of the effective layout budget
after `@context budget` was applied.
Verified: 477 workspace tests pass (12 new in
tests/spec_conformance_regressions.rs), smoke_examples_spec.sh and
spec_matrix_examples.sh both green, cargo fmt clean, no new clippy
findings.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
§11.3 asked implementations to truncate "not below min" and to drop a section once `size[i] == min`. When a section declares a `min` larger than its own content, neither branch applies: it cannot be truncated (already below min) and never satisfies the equality, so a conforming implementation terminates with a layout that exceeds B — the one guarantee the Token Box Model exists to provide. Adds `effective_min[i] = min(min[i], size[i])` and states that `min` is a floor on retained content, never a way to exceed the budget. Recorded in §21 as a targeted normative clarification within v2.1.3. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`cargo clippy --all-targets --all-features -- -D warnings` is a required CI job, and three findings fail it on current stable (they postdate the last green run in April): - two `collapsible_match` in the assertion parser — rewritten as match guards, which is also how the neighbouring arms already read - one `unnecessary_sort_by` in the layout stable-order restore No behaviour change; 477 tests, smoke and matrix scripts still green. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Found while writing a real FACET contract end to end against
facet-fct 0.1.2. Each defect makes a documented, spec-required construct unusable.#) fails the whole document withF003: Unclosed delimiteris_notrequired at least one@inputvalidated only primitives andanylist<T>,map<string,T>,struct {...}, unions, multimodal) failedF453on conforming values — structured state could not be passed to a contract at allminlarger than a section's contentjson()lensValueNode({"kind":"Map","value":...}) into rendered content and ignoredindentwhen passed as a named argrun --format json | jqwas impossible, andscripts/spec_matrix_examples.shhad to strip logs to workRepro for #3, which is the one that silently breaks a guarantee rather than failing loudly:
Approach
fct_validator::runtime_value_matches_typeparses the declared FTS type expression and matches the value.intis still widened tofloatper §8.4. This adds afct-engine → fct-validatordependency (acyclic).minto the section size before the truncate and drop decisions. §11.3 does not coversize < minat all, so the spec is updated in the same PR (effective_min[i] = min(min[i], size[i]), recorded in §21 as a targeted normative clarification within v2.1.3). The same clarification went intofacet-standardas dfc3d7b.--verbosefrom installing a second global subscriber, and reports the effective layout budget (after@context budget) instead of the host default.Verification
tests/spec_conformance_regressions.rs(including negative cases:list<string>still rejects a list of ints, a struct still rejects a missing required field)scripts/smoke_examples_spec.shandscripts/spec_matrix_examples.shboth greencargo fmt --all -- --checkclean; no new clippy findings (the 3 existing ones under clippy 1.97 are pre-existing and untouched)🤖 Generated with Claude Code