Changelog
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog,
and this project follows pre-1.0 Semantic Versioning (0.y.z).
[Unreleased]
Added
- Predicate identity: public
PredicateKeyandpredicate_key()accessors onLiteralandBodyLogicLiteralexpose functor plus arity, with diagnosticfunctor/arityformatting. Argument values, negation, modality, and temporal bounds are excluded; arithmetic body argument positions are counted. Arity usesusizeso construction and extraction are infallible (#33). - Aggregation in SPL: named
aggpremises (sum,count,min-of,max-of) and explicit(bind ?result (fold ...))expressions.- Aggregate over completed, positively proved predicates, including derived rows, with grouping and inferred strata. Cycles through aggregates are rejected.
- Distinct rows contribute separately even when their selected values match; multiple proofs of the same row contribute once.
- Results bind directly without an enumerated output domain.
sumandcountreturn zero on empty input;min-ofandmax-offail the premise. - Snapshot premises preserve defeasible evidence, source labels, and priorities; internal snapshot predicates are hidden from conclusions.
- Checked integer arithmetic and bounded grounding report overflow or exhausted budgets as errors. The aggregate bridge currently excludes decimal/float, modal, temporal, and trust-weighted inputs.
- Syntax, embedding guidance, and a runnable example in Aggregation and extension functions.
- Extension functions:
ExtensionFunction,FunctionRegistry, andPrepareOptions::function_registrysupport host-registered pure functions, integer/symbol value bindings, and custom named aggregators. The builtin prelude includes arithmetic,round(half-to-even),floor, andceil. - Trust diminishment: applicable but overruled defeaters reduce defeasible
conclusion credibility multiplicatively using their weakest-link degrees.
Thresholds use the diminished degree,
WeightedConclusion::diminished_byrecords the challenges, and definite conclusions are exempt. - Lean verification and differential testing: models and proofs for grounding, arithmetic, temporal intervals, query operators, and trust. Aggregate coverage includes dependency/stratum inference, source semantics, lowering, and completed-prefix equivalence for all four proof tags. Rust/Lean oracle suites compare supported fragments; these do not establish whole-language Rust conformance or verify custom extension implementations.
- Verification gate: builds Lean libraries and oracle executables, rejects admitted proofs and local axioms, checks for vacuous proofs, and audits theorem dependencies.
- Aggregate benchmarks:
make bench-aggregationmeasures preparation and full reasoning across row counts, groups, unrelated facts, and chained stages, with a documented local baseline. - Predicate model and vocabulary (SPEC-024): a structural predicate identity
and derived tooling projections, all additive and non-semantic (reasoning is
unchanged).
PredicateSymbol(functor + arity) with aHasPredicateSymbolprojection forLiteralandBodyLogicLiteral(body arity retains arithmetic args).- Primitive sorts, checked
PredicateSignature, positionalArgumentProfile, and non-semanticShapevalidation. GroundLiteral/LiteralPatternphase wrappers andLiteral::classify.TheorySignature::deriveandVocabulary::derive(deterministic symbol sets, declaration conflict handling, descriptions, provenance, summary counts).- SPL: first-class
(predicate name ((arg sort) ...))declarations and structured(meta (predicate functor arity) ...)metadata targets, stored inTheorywith source provenance. Undeclared predicates remain valid. Declarations also accept inlinemetaproperties ((predicate name (...) (description "..."))) as sugar for the separate metadata target. - Predicate-indicator recognizer (
functor/arity) inspindle-parser. - Additive
spindle.vocabulary/1JSON DTOs inspindle-contract. Theory::metadata()retains its label-keyed API; predicate metadata is available separately throughTheory::predicate_metadata().
- Arithmetic module (SPEC-017): full arithmetic expression support in SPL.
Termenum withSymbol,Integer,Decimal,Floatvariants.FiniteFloatwrapper: rejects NaN/Inf, normalizes-0.0, safe forEq/Hash.ArithExprAST withNaryOp(+,-,*,/,min,max),BinOp(div,rem,**), andUnaryOp(abs).ArithConstraint:bindvariable binding and comparison guards (=,!=,<,>,<=,>=).BodyLiteral,BodyLogicLiteral, andBodyArgtypes for mixed logic/arithmetic rule bodies.- Cross-type numeric matching in grounding (REQ-010/CON-005):
Integer(2)matchesDecimal(2.0)matchesFloat(2.0). - Type promotion chain: Integer -> Decimal -> Float.
rust_decimaldependency for fixed-precision decimal arithmetic.
- SPL parser extensions:
- Arithmetic expression parser for
+,-,*,/,div,rem,**,abs,min,max. (bind ?var expr)and comparison guard parsing in rule bodies.- Arithmetic expressions in body literal argument positions.
- Numeric literal detection in predicate arguments.
- Lexer extended to accept operator characters in atoms.
- Parse-time guard checks: reserved keyword rejection (REQ-008), arithmetic in head rejection (REQ-009), negated arithmetic rejection (REQ-011).
- Arithmetic expression parser for
- v2 JSON output (REQ-012/CON-006):
--v2flag on CLI,reasonV2method on WASM.- Typed
Termarguments in JSON schema (spindle.reason.v2).
- Test suites:
- Unit tests for
Term,ArithExpr, and type promotion (TEST-001, TEST-002, TEST-005). - Arithmetic parsing and guard enforcement integration tests.
- Grounding integration tests with arithmetic pipeline.
- Worked examples, NFR, and proptest suites for arithmetic.
- v2 JSON typed argument serialization tests (TEST-012).
- Unit tests for
Changed
- Reasoning semantics: Rust and the standard Lean oracles now follow traditional ambiguity-blocking DL(∂) with four constructive proof tags. Unsupported cycles remain undecided instead of receiving automatic negative conclusions; undecided attackers are not discarded. Contradictory definite facts retain both positive definite and defeasible tags without proving unrelated literals.
- Breaking: arithmetic expressions use registry-dispatched
ArithExpr::Callnodes, replacing the operator-specific AST variants, withValueandFoldvariants for general bindings and aggregation. - Projection snapshots and abduction output use deterministic, injective semantic keys, preserving distinct temporal windows and typed terms.
- CI workflows restored for Forgejo compatibility.
- Documentation book uses a forge-neutral repository icon and canonical repository source links in place of edit links (#37, contributed by SamB).
- Refreshed the documentation book with aggregation and verification guides, current DL(∂) semantics, query and WASM APIs, trust diminishment, and aggregate performance guidance. The book includes this changelog directly.
- Breaking: bounded temporal queries now match exact windows (SPEC-020
REQ-006).
query,requires,what_if, andabducegoals carrying a bounded temporal window (e.g.p@[1,10]) only match conclusions with the identical window. Previously the window was ignored, so a bounded query matched any conclusion in the same family — including atemporalporp@[20,30]. A query window strictly contained in a proven window (queryp@[1,10]vs provenp@[0,20]) now also returnsunknown. This applies to CLI queries (spindle query/requires) and WASM query methods. The JSON envelope schemas (spindle.query.v1,spindle.requires.v2) are unchanged; only the reported status for bounded queries differs. Atemporal queries still match any family member. Callquery_with_match_mode(theory, literal, QueryMatchMode::Family)to restore family-wide matching for a bounded literal. - Breaking:
AbductionSolution.factschanged fromHashSet<Literal>toVec<Literal>, deduplicated by injective canonical key so distinct temporal windows and typed terms are no longer collapsed. - Breaking:
AbductionSolution.rules_usednow lists only the rules that produce that specific solution's fact-set, not every rule whose head matches the goal. - Breaking:
From<NumericValue> for Termreplaced withTryFrom<NumericValue> for Term. Non-finite floats (NaN, Inf) now return an error instead of silently coercing to0.0. Literal::predicate_idsmigrated fromVec<SymbolId>toVec<Term>.Substitution::termsmigrated fromSymbolIdvalues toTermvalues.RuleBodymigrated fromSmallVec<[Literal; 4]>toSmallVec<[BodyLiteral; 4]>.- Body literals evaluated in source order with threaded substitutions.
- Temporal variables rejected as arithmetic operands (REQ-006).
Fixed
- Documentation examples now use complementary defeater heads and defeasible defaults correctly. Temporal documentation describes current interval variables, Allen constraints, and family matching instead of the removed bridge stage.
- Explanation witnesses: explanations on original quantified theories now use actual grounded rule instances, preserving consistent variable bindings across the conclusion and every premise. Incomplete derivations return no proof tree instead of a partial justification (#37).
why_notinspects grounded rules so variable-headed rules report actual blockers. Superiority checks use template labels, and defeated rules are no longer projected as supporting proofs.what_ifdeduplicates new conclusions proven at both positive tags while preserving distinct typed arguments and temporal windows.- Predicate declarations and metadata survive grounding, wildcard rewriting, and temporal filtering. Vocabulary reports retain conflicting declarations and their provenance; deferred shape checks no longer count as mismatches.
- Vocabulary DTO validation rejects malformed functors and inconsistent diagnostics while accepting coherent v1 signatures that omit declaration origins. SPL rejects malformed metadata properties, and WASM output quotes structured predicate metadata targets correctly.
- Symbol-valued extension returns bind correctly, and float-to-integer boundary checks reject out-of-range values.
- Reasoning tracks repeated body occurrences per slot and discards attackers with disproved premises consistently.
FiniteFloatserde deserialization now validates throughFiniteFloat::new, preventing non-canonical values (-0.0) and non-finite values from bypassing type invariants.BinArithOp::PowDisplay emits**(matching the SPL parser) instead ofpow.BodyLogicLiteral::to_spl()rendersBodyArg::Arithdirectly instead of quoting throughrender_spl_atom, preserving arithmetic s-expression syntax on round-trip.- Tilde-negated reserved keywords (
~>,~bind, etc.) rejected in list-form literals in both body and head parsers (REQ-008). - Negative base with fractional exponent rejected in
decimal_pow. - Bind consistency enforced; constant arithmetic args grounded correctly; numeric parsing unified across paths.
- Temporal bounds preserved in body normalization.
- Non-finite floats rejected in bind evaluation.
- Arithmetic module memory leaks resolved; duplicate fact double-decrement fixed.
[0.2.0]
Added
- Verified
requirescore API:requires_with_options(theory, goal, options)RequiresOptions,RequiresResult,RequiresSearchStatus,RequiresVerificationStats
- New CLI contract schema:
spindle.requires.v2. - New core test suite:
crates/spindle-core/tests/requires_verified_tests.rs.
Changed
requiresis now verified-by-default in core and CLI.requires --jsonemitsspindle.requires.v2only.spindle capabilities --jsonnow advertisesschemas.requires = spindle.requires.v2.- Core
requires()compatibility wrapper now delegates to verified logic.
Fixed
- Eliminated false-positive
requirescandidates that fail under full defeasible reasoning. - Corrected
BudgetExhaustedclassification for duplicate raw-candidate edge cases. - Added defensive collision handling for injected verification fact labels.
Migration
- Clients checking
requiresJSON need thespindle.requires.v2schema instead ofspindle.requires.v1. - In v2,
satisfied=falsewithsolutions=[]is valid.