Clean up inconsistencies in public API and documentation#88
Draft
DRMacIver wants to merge 11 commits into
Draft
Conversation
The engine produces structured date/time values, but the wrappers serialized them to ISO 8601 strings and discarded the structure — and the string shape was bimodal (fractional seconds appeared only when the microsecond was nonzero, copying Python's isoformat() wart). Introduce public hegel::Date, hegel::Time, and hegel::DateTime aggregates (C++17-compatible) with chronological comparison operators, to_string(), and operator<<, and change the three generators to return them. to_string() always prints the six-digit fractional-seconds field, so every value now has exactly one canonical serialization. Breaking change: dates()/times()/datetimes() previously returned Generator<std::string>; use to_string() or .map(...) to recover the string form. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The previous doc claimed Hegel "doesn't let you" filter — describing the exact method it was documenting — and repeated a garbled duplicate of the same paragraph. Replace it with an accurate description: up to three attempts per draw with rejected attempts discarded, then the whole test case is rejected via assume(false) (subject to the FilterTooMuch health check), plus the standard advice to prefer construction over filtration. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
register_blob stored only the first blob of the vector it was handed and silently no-op'd when a second HEGEL_REPRODUCE_FAILURE was registered for the same test, so extra blobs and later registrations vanished without a trace. Matching the family convention (hegel-rust documents stacked reproduce_failure attributes as first-wins bookkeeping), the vector is kept and only the first blob is replayed — but now: - the registry retains every blob passed to HEGEL_REPRODUCE_FAILURE, so the bookkeeping blobs are not lost; - a duplicate same-test registration throws std::logic_error with a message naming the test (terminating loudly during static initialization) instead of being silently dropped; - the hegel::test() and HEGEL_REPRODUCE_FAILURE docs state the first-wins rule unambiguously. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ll_tests Since 0.5.0 a single failing example rethrows the test body's ORIGINAL exception, but the @throws doc still claimed std::runtime_error was thrown whenever a test case fails. Document the actual contract: the body's own exception is rethrown as-is, and std::runtime_error is reserved for run errors, non-reproducing blobs, and the multiple-failures report. run_all_tests() caught only const std::exception&, so a registered test whose body threw anything else (an int, a string literal, a custom type) escaped the sweep and terminated the process — violating its documented "returns 1 if any test failed". Catch everything, count it as a failure, and report the demangled exception type to stderr. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The docs described Hypothesis and the pre-0.4.0 subprocess protocol
("routing every draw through Hypothesis"), simultaneously advertised
use with any <random> distribution and warned that doing so can hang,
and documented a parameter named tc as @param data. They also never
mentioned that a default-mode HegelRandom holds a pointer into the
TestCase and must not outlive the test-case callback.
Rewrite them from scratch: what the default (test-case-backed,
shrinkable) mode does, what true-random mode does, one coherent
recommendation (use true-random mode with <random> distributions and
whenever the value distribution matters; default mode for code that
consumes the raw bits), the corrected @param name, and a prominent
lifetime warning.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The doc said "(used by TUI)", but no TUI exists in this project. Document the real behavior: Quiet suppresses notes, drawn-value replay output, failure headers, and reproduction blobs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…fields override() claimed to "replace" a field's generator but actually drew the full default struct first and assigned the override's value over it. The dead default draw still consumed entropy, cost, and health-check pressure, and left a junk draw in the choice sequence that hampered shrinking. Rebuild the struct draw field-by-field instead: each field consults the accumulated overrides (matched by member address) and draws only from its override generator when one exists; the default generator for that field is never invoked. Chained override() calls now extend the override set rather than stacking a second full draw, and the most recent override of a field wins — the observable values are unchanged from before (later assignment already won), but only the winning generator draws. Regression test counts engine draws through the Verbose draw trace: a Person with `name` overridden by a draw-free just() must log exactly one "Generated:" line (the remaining int field), where the old behavior logged two. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The README showed `Generated: [0,0]`, but the library never renders a composite value: the draw trace prints one `Generated:` line per primitive draw. It also showed a `Hegel test failed:` prefix that no longer exists (the test's own exception is rethrown since 0.5.0) and a platform-specific libc++abi terminate line. Replace the block with the output of actually running the example (Linux/libstdc++), and explain what the per-primitive lines mean. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Follows the repo's changelog convention (RELEASE-sample.md): the release automation folds this file into CHANGELOG.md with the next version number, so user-visible changes are documented there in the existing format. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Formatting-only pass over the files touched by the preceding commits, via `just format`, so `just check-format` passes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
generators.cpp uses hegel::Date/Time/DateTime but picked hegel/datetime.h up only transitively, which misc-include-cleaner rejects; include it directly. datetime.h's comparison operators, stream inserters, and to_string() methods were missing the doc comments that the Doxyfile's WARN_AS_ERROR + WARN_NO_PARAMDOC settings require for every public symbol, parameter, and return value. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
b68b116 to
18a13de
Compare
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.
Implementation details (AI-generated)
Fixes from a documentation-vs-behavior audit of the public API:
hegel/datetime.hwith typedhegel::Date/Time/DateTime; the temporal generators return these instead of strings (zerover, breaking change). C++17-clean, with six-digit fractional-second formatting matching hegel-rust.filter()docs describe the real semantics: three attempts per draw, then the test case is rejected (not "retries until satisfied").HEGEL_REPRODUCE_FAILUREhandlers for the same test now throws instead of silently ignoring the second; first-wins replay behavior is kept and documented.run_all_testsno longer aborts on a non-std::exceptionthrow — it is caught and counted as a failure like any other.randoms()docs rewritten to describe what it actually is (engine-backed PRNG draws, replayable), with a prominent lifetime warning; the previous description of a Hypothesis-style wire protocol was fiction.override()on derived generators genuinely skips the overridden fields' default draws (verified by draw-trace counting) instead of drawing and discarding.Verification: 322/322 ctest, the C++17 consumer compile check, and format check pass. clang-tidy and doxygen jobs were not runnable in the audit environment — CI should confirm those two.
🤖 Generated with Claude Code